<commit_before>package libcontainer

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime/debug"
	"strconv"

	securejoin "github.com/cyphar/filepath-securejoin"
	"github.com/moby/sys/mountinfo"
	"golang.org/x/sys/unix"

	"github.com/opencontainers/runc/libcontainer/cgroups/manager"
	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/configs/validate"
	"github.com/opencontainers/runc/libcontainer/intelrdt"
	"github.com/opencontainers/runc/libcontainer/utils"
	"github.com/sirupsen/logrus"
)

const (
	stateFilename    = "state.json"
	execFifoFilename = "exec.fifo"
)

var idRegex = regexp.MustCompile(`^[\w+-\.]+$`)

// InitArgs returns an options func to configure a LinuxFactory with the
// provided init binary path and arguments.
func InitArgs(args ...string) func(*LinuxFactory) error {
	return func(l *LinuxFactory) (err error) {
		if len(args) > 0 {
			// Resolve relative paths to ensure that its available
			// after directory changes.
			if args[0], err = filepath.Abs(args[0]); err != nil {
				// The only error returned from filepath.Abs is
				// the one from os.Getwd, i.e. a system error.
				return err
			}
		}

		l.InitArgs = args
		return nil
	}
}

// IntelRdtfs is an options func to configure a LinuxFactory to return
// containers that use the Intel RDT "resource control" filesystem to
// create and manage Intel RDT resources (e.g., L3 cache, memory bandwidth).
func IntelRdtFs(l *LinuxFactory) error {
	if !intelrdt.IsCATEnabled() && !intelrdt.IsMBAEnabled() {
		l.NewIntelRdtManager = nil
	} else {
		l.NewIntelRdtManager = func(config *configs.Config, id string, path string) intelrdt.Manager {
			return intelrdt.NewManager(config, id, path)
		}
	}
	return nil
}

// TmpfsRoot is an option func to mount LinuxFactory.Root to tmpfs.
func TmpfsRoot(l *LinuxFactory) error {
	mounted, err := mountinfo.Mounted(l.Root)
	if err != nil {
		return err
	}
	if !mounted {
		if err := mount("tmpfs", l.Root, "", "tmpfs", 0, ""); err != nil {
			return err
		}
	}
	return nil
}

// CriuPath returns an option func to configure a LinuxFactory with the
// provided criupath
func CriuPath(criupath string) func(*LinuxFactory) error {
	return func(l *LinuxFactory) error {
		l.CriuPath = criupath
		return nil
	}
}

// New returns a linux based container factory based in the root directory and
// configures the factory with the provided option funcs.
func New(root string, options ...func(*LinuxFactory) error) (Factory, error) {
	if root != "" {
		if err := os.MkdirAll(root, 0o700); err != nil {
			return nil, err
		}
	}
	l := &LinuxFactory{
		Root:      root,
		InitPath:  "/proc/self/exe",
		InitArgs:  []string{os.Args[0], "init"},
		Validator: validate.New(),
		CriuPath:  "criu",
	}

	for _, opt := range options {
		if opt == nil {
			continue
		}
		if err := opt(l); err != nil {
			return nil, err
		}
	}
	return l, nil
}

// LinuxFactory implements the default factory interface for linux based systems.
type LinuxFactory struct {
	// Root directory for the factory to store state.
	Root string

	// InitPath is the path for calling the init responsibilities for spawning
	// a container.
	InitPath string

	// InitArgs are arguments for calling the init responsibilities for spawning
	// a container.
	InitArgs []string

	// CriuPath is the path to the criu binary used for checkpoint and restore of
	// containers.
	CriuPath string

	// New{u,g}idmapPath is the path to the binaries used for mapping with
	// rootless containers.
	NewuidmapPath string
	NewgidmapPath string

	// Validator provides validation to container configurations.
	Validator validate.Validator

	// NewIntelRdtManager returns an initialized Intel RDT manager for a single container.
	NewIntelRdtManager func(config *configs.Config, id string, path string) intelrdt.Manager
}

func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, error) {
	if l.Root == "" {
		return nil, errors.New("root not set")
	}
	if err := l.validateID(id); err != nil {
		return nil, err
	}
	if err := l.Validator.Validate(config); err != nil {
		return nil, err
	}
	containerRoot, err := securejoin.SecureJoin(l.Root, id)
	if err != nil {
		return nil, err
	}
	if _, err := os.Stat(containerRoot); err == nil {
		return nil, ErrExist
	} else if !os.IsNotExist(err) {
		return nil, err
	}

	cm, err := manager.New(config.Cgroups)
	if err != nil {
		return nil, err
	}

	// Check that cgroup does not exist or empty (no processes).
	// Note for cgroup v1 this check is not thorough, as there are multiple
	// separate hierarchies, while both Exists() and GetAllPids() only use
	// one for "devices" controller (assuming others are the same, which is
	// probably true in almost all scenarios). Checking all the hierarchies
	// would be too expensive.
	if cm.Exists() {
		pids, err := cm.GetAllPids()
		// Reading PIDs can race with cgroups removal, so ignore ENOENT and ENODEV.
		if err != nil && !errors.Is(err, os.ErrNotExist) && !errors.Is(err, unix.ENODEV) {
			return nil, fmt.Errorf("unable to get cgroup PIDs: %w", err)
		}
		if len(pids) != 0 {
			// TODO: return an error.
			logrus.Warnf("container's cgroup is not empty: %d process(es) found", len(pids))
			logrus.Warn("DEPRECATED: running container in a non-empty cgroup won't be supported in runc 1.2; https://github.com/opencontainers/runc/issues/3132")
		}
	}

	// Check that cgroup is not frozen. Do not use Exists() here
	// since in cgroup v1 it only checks "devices" controller.
	st, err := cm.GetFreezerState()
	if err != nil {
		return nil, fmt.Errorf("unable to get cgroup freezer state: %w", err)
	}
	if st == configs.Frozen {
		return nil, errors.New("container's cgroup unexpectedly frozen")
	}

	if err := os.MkdirAll(containerRoot, 0o711); err != nil {
		return nil, err
	}
	if err := os.Chown(containerRoot, unix.Geteuid(), unix.Getegid()); err != nil {
		return nil, err
	}
	c := &linuxContainer{
		id:            id,
		root:          containerRoot,
		config:        config,
		initPath:      l.InitPath,
		initArgs:      l.InitArgs,
		criuPath:      l.CriuPath,
		newuidmapPath: l.NewuidmapPath,
		newgidmapPath: l.NewgidmapPath,
		cgroupManager: cm,
	}
	if l.NewIntelRdtManager != nil {
		c.intelRdtManager = l.NewIntelRdtManager(config, id, "")
	}
	c.state = &stoppedState{c: c}
	return c, nil
}

func (l *LinuxFactory) Load(id string) (Container, error) {
	if l.Root == "" {
		return nil, errors.New("root not set")
	}
	// when load, we need to check id is valid or not.
	if err := l.validateID(id); err != nil {
		return nil, err
	}
	containerRoot, err := securejoin.SecureJoin(l.Root, id)
	if err != nil {
		return nil, err
	}
	state, err := l.loadState(containerRoot)
	if err != nil {
		return nil, err
	}
	r := &nonChildProcess{
		processPid:       state.InitProcessPid,
		processStartTime: state.InitProcessStartTime,
		fds:              state.ExternalDescriptors,
	}
	cm, err := manager.NewWithPaths(state.Config.Cgroups, state.CgroupPaths)
	if err != nil {
		return nil, err
	}
	c := &linuxContainer{
		initProcess:          r,
		initProcessStartTime: state.InitProcessStartTime,
		id:                   id,
		config:               &state.Config,
		initPath:             l.InitPath,
		initArgs:             l.InitArgs,
		criuPath:             l.CriuPath,
		newuidmapPath:        l.NewuidmapPath,
		newgidmapPath:        l.NewgidmapPath,
		cgroupManager:        cm,
		root:                 containerRoot,
		created:              state.Created,
	}
	if l.NewIntelRdtManager != nil {
		c.intelRdtManager = l.NewIntelRdtManager(&state.Config, id, state.IntelRdtPath)
	}
	c.state = &loadedState{c: c}
	if err := c.refreshState(); err != nil {
		return nil, err
	}
	return c, nil
}

func (l *LinuxFactory) Type() string {
	return "libcontainer"
}

// StartInitialization loads a container by opening the pipe fd from the parent to read the configuration and state
// This is a low level implementation detail of the reexec and should not be consumed externally
func (l *LinuxFactory) StartInitialization() (err error) {
	// Get the INITPIPE.
	envInitPipe := os.Getenv("_LIBCONTAINER_INITPIPE")
	pipefd, err := strconv.Atoi(envInitPipe)
	if err != nil {
		err = fmt.Errorf("unable to convert _LIBCONTAINER_INITPIPE: %w", err)
		logrus.Error(err)
		return err
	}
	pipe := os.NewFile(uintptr(pipefd), "pipe")
	defer pipe.Close()

	defer func() {
		// We have an error during the initialization of the container's init,
		// send it back to the parent process in the form of an initError.
		if werr := writeSync(pipe, procError); werr != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}
		if werr := utils.WriteJSON(pipe, &initError{Message: err.Error()}); werr != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}
	}()

	// Only init processes have FIFOFD.
	fifofd := -1
	envInitType := os.Getenv("_LIBCONTAINER_INITTYPE")
	it := initType(envInitType)
	if it == initStandard {
		envFifoFd := os.Getenv("_LIBCONTAINER_FIFOFD")
		if fifofd, err = strconv.Atoi(envFifoFd); err != nil {
			return fmt.Errorf("unable to convert _LIBCONTAINER_FIFOFD: %w", err)
		}
	}

	var consoleSocket *os.File
	if envConsole := os.Getenv("_LIBCONTAINER_CONSOLE"); envConsole != "" {
		console, err := strconv.Atoi(envConsole)
		if err != nil {
			return fmt.Errorf("unable to convert _LIBCONTAINER_CONSOLE: %w", err)
		}
		consoleSocket = os.NewFile(uintptr(console), "console-socket")
		defer consoleSocket.Close()
	}

	logPipeFdStr := os.Getenv("_LIBCONTAINER_LOGPIPE")
	logPipeFd, err := strconv.Atoi(logPipeFdStr)
	if err != nil {
		return fmt.Errorf("unable to convert _LIBCONTAINER_LOGPIPE: %w", err)
	}

	// Get mount files (O_PATH).
	mountFds, err := parseMountFds()
	if err != nil {
		return err
	}

	// clear the current process's environment to clean any libcontainer
	// specific env vars.
	os.Clearenv()

	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("panic from initialization: %w, %v", e, string(debug.Stack()))
		}
	}()

	i, err := newContainerInit(it, pipe, consoleSocket, fifofd, logPipeFd, mountFds)
	if err != nil {
		return err
	}

	// If Init succeeds, syscall.Exec will not return, hence none of the defers will be called.
	return i.Init()
}

func (l *LinuxFactory) loadState(root string) (*State, error) {
	stateFilePath, err := securejoin.SecureJoin(root, stateFilename)
	if err != nil {
		return nil, err
	}
	f, err := os.Open(stateFilePath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, ErrNotExist
		}
		return nil, err
	}
	defer f.Close()
	var state *State
	if err := json.NewDecoder(f).Decode(&state); err != nil {
		return nil, err
	}
	return state, nil
}

func (l *LinuxFactory) validateID(id string) error {
	if !idRegex.MatchString(id) || string(os.PathSeparator)+id != utils.CleanPath(string(os.PathSeparator)+id) {
		return ErrInvalidID
	}

	return nil
}

// NewuidmapPath returns an option func to configure a LinuxFactory with the
// provided ..
func NewuidmapPath(newuidmapPath string) func(*LinuxFactory) error {
	return func(l *LinuxFactory) error {
		l.NewuidmapPath = newuidmapPath
		return nil
	}
}

// NewgidmapPath returns an option func to configure a LinuxFactory with the
// provided ..
func NewgidmapPath(newgidmapPath string) func(*LinuxFactory) error {
	return func(l *LinuxFactory) error {
		l.NewgidmapPath = newgidmapPath
		return nil
	}
}

func parseMountFds() ([]int, error) {
	fdsJson := os.Getenv("_LIBCONTAINER_MOUNT_FDS")
	if fdsJson == "" {
		// Always return the nil slice if no fd is present.
		return nil, nil
	}

	var mountFds []int
	if err := json.Unmarshal([]byte(fdsJson), &mountFds); err != nil {
		return nil, fmt.Errorf("Error unmarshalling _LIBCONTAINER_MOUNT_FDS: %w", err)
	}

	return mountFds, nil
}
<commit_msg>libct: Create: rm unneeded chown<commit_after>package libcontainer

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime/debug"
	"strconv"

	securejoin "github.com/cyphar/filepath-securejoin"
	"github.com/moby/sys/mountinfo"
	"golang.org/x/sys/unix"

	"github.com/opencontainers/runc/libcontainer/cgroups/manager"
	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/configs/validate"
	"github.com/opencontainers/runc/libcontainer/intelrdt"
	"github.com/opencontainers/runc/libcontainer/utils"
	"github.com/sirupsen/logrus"
)

const (
	stateFilename    = "state.json"
	execFifoFilename = "exec.fifo"
)

var idRegex = regexp.MustCompile(`^[\w+-\.]+$`)

// InitArgs returns an options func to configure a LinuxFactory with the
// provided init binary path and arguments.
func InitArgs(args ...string) func(*LinuxFactory) error {
	return func(l *LinuxFactory) (err error) {
		if len(args) > 0 {
			// Resolve relative paths to ensure that its available
			// after directory changes.
			if args[0], err = filepath.Abs(args[0]); err != nil {
				// The only error returned from filepath.Abs is
				// the one from os.Getwd, i.e. a system error.
				return err
			}
		}

		l.InitArgs = args
		return nil
	}
}

// IntelRdtfs is an options func to configure a LinuxFactory to return
// containers that use the Intel RDT "resource control" filesystem to
// create and manage Intel RDT resources (e.g., L3 cache, memory bandwidth).
func IntelRdtFs(l *LinuxFactory) error {
	if !intelrdt.IsCATEnabled() && !intelrdt.IsMBAEnabled() {
		l.NewIntelRdtManager = nil
	} else {
		l.NewIntelRdtManager = func(config *configs.Config, id string, path string) intelrdt.Manager {
			return intelrdt.NewManager(config, id, path)
		}
	}
	return nil
}

// TmpfsRoot is an option func to mount LinuxFactory.Root to tmpfs.
func TmpfsRoot(l *LinuxFactory) error {
	mounted, err := mountinfo.Mounted(l.Root)
	if err != nil {
		return err
	}
	if !mounted {
		if err := mount("tmpfs", l.Root, "", "tmpfs", 0, ""); err != nil {
			return err
		}
	}
	return nil
}

// CriuPath returns an option func to configure a LinuxFactory with the
// provided criupath
func CriuPath(criupath string) func(*LinuxFactory) error {
	return func(l *LinuxFactory) error {
		l.CriuPath = criupath
		return nil
	}
}

// New returns a linux based container factory based in the root directory and
// configures the factory with the provided option funcs.
func New(root string, options ...func(*LinuxFactory) error) (Factory, error) {
	if root != "" {
		if err := os.MkdirAll(root, 0o700); err != nil {
			return nil, err
		}
	}
	l := &LinuxFactory{
		Root:      root,
		InitPath:  "/proc/self/exe",
		InitArgs:  []string{os.Args[0], "init"},
		Validator: validate.New(),
		CriuPath:  "criu",
	}

	for _, opt := range options {
		if opt == nil {
			continue
		}
		if err := opt(l); err != nil {
			return nil, err
		}
	}
	return l, nil
}

// LinuxFactory implements the default factory interface for linux based systems.
type LinuxFactory struct {
	// Root directory for the factory to store state.
	Root string

	// InitPath is the path for calling the init responsibilities for spawning
	// a container.
	InitPath string

	// InitArgs are arguments for calling the init responsibilities for spawning
	// a container.
	InitArgs []string

	// CriuPath is the path to the criu binary used for checkpoint and restore of
	// containers.
	CriuPath string

	// New{u,g}idmapPath is the path to the binaries used for mapping with
	// rootless containers.
	NewuidmapPath string
	NewgidmapPath string

	// Validator provides validation to container configurations.
	Validator validate.Validator

	// NewIntelRdtManager returns an initialized Intel RDT manager for a single container.
	NewIntelRdtManager func(config *configs.Config, id string, path string) intelrdt.Manager
}

func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, error) {
	if l.Root == "" {
		return nil, errors.New("root not set")
	}
	if err := l.validateID(id); err != nil {
		return nil, err
	}
	if err := l.Validator.Validate(config); err != nil {
		return nil, err
	}
	containerRoot, err := securejoin.SecureJoin(l.Root, id)
	if err != nil {
		return nil, err
	}
	if _, err := os.Stat(containerRoot); err == nil {
		return nil, ErrExist
	} else if !os.IsNotExist(err) {
		return nil, err
	}

	cm, err := manager.New(config.Cgroups)
	if err != nil {
		return nil, err
	}

	// Check that cgroup does not exist or empty (no processes).
	// Note for cgroup v1 this check is not thorough, as there are multiple
	// separate hierarchies, while both Exists() and GetAllPids() only use
	// one for "devices" controller (assuming others are the same, which is
	// probably true in almost all scenarios). Checking all the hierarchies
	// would be too expensive.
	if cm.Exists() {
		pids, err := cm.GetAllPids()
		// Reading PIDs can race with cgroups removal, so ignore ENOENT and ENODEV.
		if err != nil && !errors.Is(err, os.ErrNotExist) && !errors.Is(err, unix.ENODEV) {
			return nil, fmt.Errorf("unable to get cgroup PIDs: %w", err)
		}
		if len(pids) != 0 {
			// TODO: return an error.
			logrus.Warnf("container's cgroup is not empty: %d process(es) found", len(pids))
			logrus.Warn("DEPRECATED: running container in a non-empty cgroup won't be supported in runc 1.2; https://github.com/opencontainers/runc/issues/3132")
		}
	}

	// Check that cgroup is not frozen. Do not use Exists() here
	// since in cgroup v1 it only checks "devices" controller.
	st, err := cm.GetFreezerState()
	if err != nil {
		return nil, fmt.Errorf("unable to get cgroup freezer state: %w", err)
	}
	if st == configs.Frozen {
		return nil, errors.New("container's cgroup unexpectedly frozen")
	}

	if err := os.MkdirAll(containerRoot, 0o711); err != nil {
		return nil, err
	}
	c := &linuxContainer{
		id:            id,
		root:          containerRoot,
		config:        config,
		initPath:      l.InitPath,
		initArgs:      l.InitArgs,
		criuPath:      l.CriuPath,
		newuidmapPath: l.NewuidmapPath,
		newgidmapPath: l.NewgidmapPath,
		cgroupManager: cm,
	}
	if l.NewIntelRdtManager != nil {
		c.intelRdtManager = l.NewIntelRdtManager(config, id, "")
	}
	c.state = &stoppedState{c: c}
	return c, nil
}

func (l *LinuxFactory) Load(id string) (Container, error) {
	if l.Root == "" {
		return nil, errors.New("root not set")
	}
	// when load, we need to check id is valid or not.
	if err := l.validateID(id); err != nil {
		return nil, err
	}
	containerRoot, err := securejoin.SecureJoin(l.Root, id)
	if err != nil {
		return nil, err
	}
	state, err := l.loadState(containerRoot)
	if err != nil {
		return nil, err
	}
	r := &nonChildProcess{
		processPid:       state.InitProcessPid,
		processStartTime: state.InitProcessStartTime,
		fds:              state.ExternalDescriptors,
	}
	cm, err := manager.NewWithPaths(state.Config.Cgroups, state.CgroupPaths)
	if err != nil {
		return nil, err
	}
	c := &linuxContainer{
		initProcess:          r,
		initProcessStartTime: state.InitProcessStartTime,
		id:                   id,
		config:               &state.Config,
		initPath:             l.InitPath,
		initArgs:             l.InitArgs,
		criuPath:             l.CriuPath,
		newuidmapPath:        l.NewuidmapPath,
		newgidmapPath:        l.NewgidmapPath,
		cgroupManager:        cm,
		root:                 containerRoot,
		created:              state.Created,
	}
	if l.NewIntelRdtManager != nil {
		c.intelRdtManager = l.NewIntelRdtManager(&state.Config, id, state.IntelRdtPath)
	}
	c.state = &loadedState{c: c}
	if err := c.refreshState(); err != nil {
		return nil, err
	}
	return c, nil
}

func (l *LinuxFactory) Type() string {
	return "libcontainer"
}

// StartInitialization loads a container by opening the pipe fd from the parent to read the configuration and state
// This is a low level implementation detail of the reexec and should not be consumed externally
func (l *LinuxFactory) StartInitialization() (err error) {
	// Get the INITPIPE.
	envInitPipe := os.Getenv("_LIBCONTAINER_INITPIPE")
	pipefd, err := strconv.Atoi(envInitPipe)
	if err != nil {
		err = fmt.Errorf("unable to convert _LIBCONTAINER_INITPIPE: %w", err)
		logrus.Error(err)
		return err
	}
	pipe := os.NewFile(uintptr(pipefd), "pipe")
	defer pipe.Close()

	defer func() {
		// We have an error during the initialization of the container's init,
		// send it back to the parent process in the form of an initError.
		if werr := writeSync(pipe, procError); werr != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}
		if werr := utils.WriteJSON(pipe, &initError{Message: err.Error()}); werr != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}
	}()

	// Only init processes have FIFOFD.
	fifofd := -1
	envInitType := os.Getenv("_LIBCONTAINER_INITTYPE")
	it := initType(envInitType)
	if it == initStandard {
		envFifoFd := os.Getenv("_LIBCONTAINER_FIFOFD")
		if fifofd, err = strconv.Atoi(envFifoFd); err != nil {
			return fmt.Errorf("unable to convert _LIBCONTAINER_FIFOFD: %w", err)
		}
	}

	var consoleSocket *os.File
	if envConsole := os.Getenv("_LIBCONTAINER_CONSOLE"); envConsole != "" {
		console, err := strconv.Atoi(envConsole)
		if err != nil {
			return fmt.Errorf("unable to convert _LIBCONTAINER_CONSOLE: %w", err)
		}
		consoleSocket = os.NewFile(uintptr(console), "console-socket")
		defer consoleSocket.Close()
	}

	logPipeFdStr := os.Getenv("_LIBCONTAINER_LOGPIPE")
	logPipeFd, err := strconv.Atoi(logPipeFdStr)
	if err != nil {
		return fmt.Errorf("unable to convert _LIBCONTAINER_LOGPIPE: %w", err)
	}

	// Get mount files (O_PATH).
	mountFds, err := parseMountFds()
	if err != nil {
		return err
	}

	// clear the current process's environment to clean any libcontainer
	// specific env vars.
	os.Clearenv()

	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("panic from initialization: %w, %v", e, string(debug.Stack()))
		}
	}()

	i, err := newContainerInit(it, pipe, consoleSocket, fifofd, logPipeFd, mountFds)
	if err != nil {
		return err
	}

	// If Init succeeds, syscall.Exec will not return, hence none of the defers will be called.
	return i.Init()
}

func (l *LinuxFactory) loadState(root string) (*State, error) {
	stateFilePath, err := securejoin.SecureJoin(root, stateFilename)
	if err != nil {
		return nil, err
	}
	f, err := os.Open(stateFilePath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, ErrNotExist
		}
		return nil, err
	}
	defer f.Close()
	var state *State
	if err := json.NewDecoder(f).Decode(&state); err != nil {
		return nil, err
	}
	return state, nil
}

func (l *LinuxFactory) validateID(id string) error {
	if !idRegex.MatchString(id) || string(os.PathSeparator)+id != utils.CleanPath(string(os.PathSeparator)+id) {
		return ErrInvalidID
	}

	return nil
}

// NewuidmapPath returns an option func to configure a LinuxFactory with the
// provided ..
func NewuidmapPath(newuidmapPath string) func(*LinuxFactory) error {
	return func(l *LinuxFactory) error {
		l.NewuidmapPath = newuidmapPath
		return nil
	}
}

// NewgidmapPath returns an option func to configure a LinuxFactory with the
// provided ..
func NewgidmapPath(newgidmapPath string) func(*LinuxFactory) error {
	return func(l *LinuxFactory) error {
		l.NewgidmapPath = newgidmapPath
		return nil
	}
}

func parseMountFds() ([]int, error) {
	fdsJson := os.Getenv("_LIBCONTAINER_MOUNT_FDS")
	if fdsJson == "" {
		// Always return the nil slice if no fd is present.
		return nil, nil
	}

	var mountFds []int
	if err := json.Unmarshal([]byte(fdsJson), &mountFds); err != nil {
		return nil, fmt.Errorf("Error unmarshalling _LIBCONTAINER_MOUNT_FDS: %w", err)
	}

	return mountFds, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"sync"

	"github.com/spf13/cobra"

	"github.com/Shopify/themekit/src/cmdutil"
	"github.com/Shopify/themekit/src/colors"
	"github.com/Shopify/themekit/src/file"
	"github.com/Shopify/themekit/src/shopify"
)

const settingsDataKey = "config/settings_data.json"

var (
	deployCmd = &cobra.Command{
		Use:   "deploy <filenames>",
		Short: "deploy files to shopify",
		Long: `Deploy will overwrite specific files if provided with file names.
 If deploy is not provided with file names then it will deploy all
 the files on shopify with your local files. Any files that do not
 exist on your local machine will be removed from shopify unless the --soft
 flag is passed

 For more documentation please see http://shopify.github.io/themekit/commands/#deploy
 `,
		RunE: func(cmd *cobra.Command, args []string) error {
			return cmdutil.ForEachClient(flags, args, deploy)
		},
	}

	replaceCmd = &cobra.Command{
		Use:   "replace <filenames>",
		Short: "Overwrite theme file(s)",
		Long: `Replace will overwrite specific files if provided with file names.
 If replace is not provided with file names then it will replace all
 the files on shopify with your local files. Any files that do not
 exist on your local machine will be removed from shopify.

  Deprecation Notice: This command is deprecated in v0.8.0 and will be removed in
	v0.8.1. Please use the 'deploy' command instead.

 For more documentation please see http://shopify.github.io/themekit/commands/#replace
 `,
		RunE: func(cmd *cobra.Command, args []string) error {
			colors.ColorStdOut.Printf("[%s] replace has been deprecated please use `deploy` instead", colors.Yellow("WARN"))
			return cmdutil.ForEachClient(flags, args, deploy)
		},
	}

	uploadCmd = &cobra.Command{
		Use:   "upload <filenames>",
		Short: "Upload theme file(s) to shopify",
		Long: `Upload will upload specific files to shopify servers if provided file names.
 If no filenames are provided then upload will upload every file in the project
 to shopify.

  Deprecation Notice: This command is deprecated in v0.8.0 and will be removed in
	v0.8.1. Please use the 'deploy' command instead.

 For more documentation please see http://shopify.github.io/themekit/commands/#upload
 `,
		RunE: func(cmd *cobra.Command, args []string) error {
			colors.ColorStdOut.Printf("[%s] upload has been deprecated please use `deploy` with the --nodelete flag instead", colors.Yellow("WARN"))
			flags.NoDelete = true
			return cmdutil.ForEachClient(flags, args, deploy)
		},
	}
)

func deploy(ctx cmdutil.Ctx) error {
	if ctx.Env.ReadOnly {
		return fmt.Errorf("[%s] environment is readonly", colors.Green(ctx.Env.Name))
	}

	assetsActions, err := generateActions(ctx)
	if err != nil {
		return err
	}

	var deployGroup sync.WaitGroup
	ctx.StartProgress(len(assetsActions))
	for path, op := range assetsActions {
		if path == settingsDataKey {
			defer perform(ctx, path, op)
			continue
		}
		deployGroup.Add(1)
		go func(path string, op file.Op) {
			defer deployGroup.Done()
			perform(ctx, path, op)
		}(path, op)
	}

	deployGroup.Wait()
	return nil
}

func generateActions(ctx cmdutil.Ctx) (map[string]file.Op, error) {
	assetsActions := map[string]file.Op{}

	if len(ctx.Args) == 0 && !ctx.Flags.NoDelete {
		remoteFiles, err := ctx.Client.GetAllAssets()
		if err != nil {
			return assetsActions, err
		}
		for _, filename := range remoteFiles {
			assetsActions[filename] = file.Remove
		}
	}

	localAssets, err := shopify.FindAssets(ctx.Env, ctx.Args...)
	if err != nil {
		return assetsActions, err
	}

	for _, path := range localAssets {
		assetsActions[path] = file.Update
	}
	return assetsActions, nil
}
<commit_msg>Fixing windows deploy filepaths<commit_after>package cmd

import (
	"fmt"
	"path/filepath"
	"sync"

	"github.com/spf13/cobra"

	"github.com/Shopify/themekit/src/cmdutil"
	"github.com/Shopify/themekit/src/colors"
	"github.com/Shopify/themekit/src/file"
	"github.com/Shopify/themekit/src/shopify"
)

const settingsDataKey = "config/settings_data.json"

var (
	deployCmd = &cobra.Command{
		Use:   "deploy <filenames>",
		Short: "deploy files to shopify",
		Long: `Deploy will overwrite specific files if provided with file names.
 If deploy is not provided with file names then it will deploy all
 the files on shopify with your local files. Any files that do not
 exist on your local machine will be removed from shopify unless the --soft
 flag is passed

 For more documentation please see http://shopify.github.io/themekit/commands/#deploy
 `,
		RunE: func(cmd *cobra.Command, args []string) error {
			return cmdutil.ForEachClient(flags, args, deploy)
		},
	}

	replaceCmd = &cobra.Command{
		Use:   "replace <filenames>",
		Short: "Overwrite theme file(s)",
		Long: `Replace will overwrite specific files if provided with file names.
 If replace is not provided with file names then it will replace all
 the files on shopify with your local files. Any files that do not
 exist on your local machine will be removed from shopify.

  Deprecation Notice: This command is deprecated in v0.8.0 and will be removed in
	v0.8.1. Please use the 'deploy' command instead.

 For more documentation please see http://shopify.github.io/themekit/commands/#replace
 `,
		RunE: func(cmd *cobra.Command, args []string) error {
			colors.ColorStdOut.Printf("[%s] replace has been deprecated please use `deploy` instead", colors.Yellow("WARN"))
			return cmdutil.ForEachClient(flags, args, deploy)
		},
	}

	uploadCmd = &cobra.Command{
		Use:   "upload <filenames>",
		Short: "Upload theme file(s) to shopify",
		Long: `Upload will upload specific files to shopify servers if provided file names.
 If no filenames are provided then upload will upload every file in the project
 to shopify.

  Deprecation Notice: This command is deprecated in v0.8.0 and will be removed in
	v0.8.1. Please use the 'deploy' command instead.

 For more documentation please see http://shopify.github.io/themekit/commands/#upload
 `,
		RunE: func(cmd *cobra.Command, args []string) error {
			colors.ColorStdOut.Printf("[%s] upload has been deprecated please use `deploy` with the --nodelete flag instead", colors.Yellow("WARN"))
			flags.NoDelete = true
			return cmdutil.ForEachClient(flags, args, deploy)
		},
	}
)

func deploy(ctx cmdutil.Ctx) error {
	if ctx.Env.ReadOnly {
		return fmt.Errorf("[%s] environment is readonly", colors.Green(ctx.Env.Name))
	}

	assetsActions, err := generateActions(ctx)
	if err != nil {
		return err
	}

	var deployGroup sync.WaitGroup
	ctx.StartProgress(len(assetsActions))
	for path, op := range assetsActions {
		if path == settingsDataKey {
			defer perform(ctx, path, op)
			continue
		}
		deployGroup.Add(1)
		go func(path string, op file.Op) {
			defer deployGroup.Done()
			perform(ctx, path, op)
		}(path, op)
	}

	deployGroup.Wait()
	return nil
}

func generateActions(ctx cmdutil.Ctx) (map[string]file.Op, error) {
	assetsActions := map[string]file.Op{}

	if len(ctx.Args) == 0 && !ctx.Flags.NoDelete {
		remoteFiles, err := ctx.Client.GetAllAssets()
		if err != nil {
			return assetsActions, err
		}
		for _, filename := range remoteFiles {
			assetsActions[filepath.ToSlash(filename)] = file.Remove
		}
	}

	localAssets, err := shopify.FindAssets(ctx.Env, ctx.Args...)
	if err != nil {
		return assetsActions, err
	}

	for _, path := range localAssets {
		assetsActions[path] = file.Update
	}
	return assetsActions, nil
}
<|endoftext|>


<commit_before>package tls

import (
	"crypto/tls"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/bosssauce/ponzu/system/db"

	"golang.org/x/crypto/acme/autocert"
)

var m autocert.Manager

// setup attempts to locate or create the cert cache directory and the certs for TLS encryption
func setup() {
	pwd, err := os.Getwd()
	if err != nil {
		log.Fatalln("Couldn't find working directory to locate or save certificates.")
	}

	cache := autocert.DirCache(filepath.Join(pwd, "system", "tls", "certs"))
	if _, err := os.Stat(string(cache)); os.IsNotExist(err) {
		err := os.MkdirAll(string(cache), os.ModePerm|os.ModeDir)
		if err != nil {
			log.Fatalln("Couldn't create cert directory at", cache)
		}
	}

	// get host/domain and email from Config to use for TLS request to Let's encryption.
	// we will fail fatally if either are not found since Let's Encrypt will rate-limit
	// and sending incomplete requests is wasteful and guarenteed to fail its check
	host, err := db.Config("domain")
	if err != nil {
		log.Fatalln("Error identifying host/domain during TLS set-up.", err)
	}

	if host == nil {
		log.Fatalln("No 'domain' field set in Configuration. Please add a domain before attempting to make certificates.")
	}
	fmt.Println("Using", host, "as host/domain for certificate...")
	fmt.Println("NOTE: if the host/domain is not configured properly or is unreachable, HTTPS set-up will fail.")

	email, err := db.Config("admin_email")
	if err != nil {
		log.Fatalln("Error identifying admin email during TLS set-up.", err)
	}

	if email == nil {
		log.Fatalln("No 'admin_email' field set in Configuration. Please add an admin email before attempting to make certificates.")
	}
	fmt.Println("Using", email, "as contact email for certificate...")

	m = autocert.Manager{
		Prompt:      autocert.AcceptTOS,
		Cache:       cache,
		HostPolicy:  autocert.HostWhitelist(string(host)),
		RenewBefore: time.Hour * 24 * 30,
		Email:       string(email),
	}

}

// Enable runs the setup for creating or locating certificates and starts the TLS server
func Enable() {
	setup()

	server := &http.Server{
		Addr:      ":443",
		TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
	}

	go log.Fatalln(server.ListenAndServeTLS("", ""))
	fmt.Println("Server listening for HTTPS requests...")
}
<commit_msg>casting var to strings for printing in shell<commit_after>package tls

import (
	"crypto/tls"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/bosssauce/ponzu/system/db"

	"golang.org/x/crypto/acme/autocert"
)

var m autocert.Manager

// setup attempts to locate or create the cert cache directory and the certs for TLS encryption
func setup() {
	pwd, err := os.Getwd()
	if err != nil {
		log.Fatalln("Couldn't find working directory to locate or save certificates.")
	}

	cache := autocert.DirCache(filepath.Join(pwd, "system", "tls", "certs"))
	if _, err := os.Stat(string(cache)); os.IsNotExist(err) {
		err := os.MkdirAll(string(cache), os.ModePerm|os.ModeDir)
		if err != nil {
			log.Fatalln("Couldn't create cert directory at", cache)
		}
	}

	// get host/domain and email from Config to use for TLS request to Let's encryption.
	// we will fail fatally if either are not found since Let's Encrypt will rate-limit
	// and sending incomplete requests is wasteful and guarenteed to fail its check
	host, err := db.Config("domain")
	if err != nil {
		log.Fatalln("Error identifying host/domain during TLS set-up.", err)
	}

	if host == nil {
		log.Fatalln("No 'domain' field set in Configuration. Please add a domain before attempting to make certificates.")
	}
	fmt.Println("Using", string(host), "as host/domain for certificate...")
	fmt.Println("NOTE: if the host/domain is not configured properly or is unreachable, HTTPS set-up will fail.")

	email, err := db.Config("admin_email")
	if err != nil {
		log.Fatalln("Error identifying admin email during TLS set-up.", err)
	}

	if email == nil {
		log.Fatalln("No 'admin_email' field set in Configuration. Please add an admin email before attempting to make certificates.")
	}
	fmt.Println("Using", string(email), "as contact email for certificate...")

	m = autocert.Manager{
		Prompt:      autocert.AcceptTOS,
		Cache:       cache,
		HostPolicy:  autocert.HostWhitelist(string(host)),
		RenewBefore: time.Hour * 24 * 30,
		Email:       string(email),
	}

}

// Enable runs the setup for creating or locating certificates and starts the TLS server
func Enable() {
	setup()

	server := &http.Server{
		Addr:      ":443",
		TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
	}

	go log.Fatalln(server.ListenAndServeTLS("", ""))
	fmt.Println("Server listening for HTTPS requests...")
}
<|endoftext|>


<commit_before>/*
Copyright 2020 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    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 cryptolib

import (
	"bytes"
	"fmt"
	"io/ioutil"

	"github.com/pkg/errors"
	"golang.org/x/crypto/openpgp"
	"golang.org/x/crypto/openpgp/armor"
)

type pgpVerifierImpl struct{}

// verifyPgp verifies a PGP signature using a public key and outputs the
// payload that was signed. `signature` is an ASCII-armored "attached"
// signature, generated by `gpg --armor --sign --output signature payload`.
// `publicKey` is an ASCII-armored PGP key.
func (v pgpVerifierImpl) verifyPgp(signature, publicKey []byte) ([]byte, error) {
	keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(publicKey))
	if err != nil {
		return nil, errors.Wrap(err, "error reading armored key ring")
	}

	armorBlock, err := armor.Decode(bytes.NewReader(signature))
	if err != nil {
		return nil, errors.Wrap(err, "error decoding armored signature")
	}

	messageDetails, err := openpgp.ReadMessage(armorBlock.Body, keyring, nil, nil)
	if err != nil {
		return nil, errors.Wrap(err, "error reading armor signature")
	}

	// MessageDetails.UnverifiedBody signature is not verified until we read it.
	// This will call PublicKey.VerifySignature for the keys in the keyring.
	payload, err := ioutil.ReadAll(messageDetails.UnverifiedBody)
	if err != nil {
		return nil, errors.Wrap(err, "error reading message contents")
	}

	// Make sure after reading the UnverifiedBody above that the Signature
	// exists and there is no SignatureError.
	if messageDetails.SignatureError != nil {
		return nil, errors.Wrap(messageDetails.SignatureError, "failed to validate: signature error")
	}
	if messageDetails.Signature == nil {
		return nil, fmt.Errorf("failed to validate: signature missing")
	}
	return payload, nil
}

type pgpSigner struct {
	privateEntity *openpgp.Entity
	publicKeyID   string
}

// NewPgpSigner creates a Signer interface for PGP Attestations. `privateKey`
// contains the ASCII-armored private key.
func NewPgpSigner(privateKey []byte) (Signer, error) {
	keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(privateKey))
	if err != nil {
		return nil, errors.Wrap(err, "error reading armored private key")
	}
	if len(keyring) != 1 {
		return nil, fmt.Errorf("expected 1 key in keyring, got %d", len(keyring))
	}
	privateEntity := keyring[0]
	return &pgpSigner{
		privateEntity: privateEntity,
		publicKeyID:   fmt.Sprintf("%X", privateEntity.PrimaryKey.Fingerprint),
	}, nil
}

// CreateAttestation creates a signed PGP Attestation. The Attestation's
// publicKeyID will be derived from the private key. See Signer for more
// details.
func (s *pgpSigner) CreateAttestation(payload []byte) (*Attestation, error) {
	// Create a buffer to store the signature
	signature := bytes.Buffer{}

	// Armor-encode the signature before writing to the buffer
	armorBuffer, err := armor.Encode(&signature, openpgp.SignatureType, nil)
	if err != nil {
		return nil, errors.Wrap(err, "error creating armor buffer")
	}

	armorWriter, err := openpgp.Sign(armorBuffer, s.privateEntity, nil, nil)
	if err != nil {
		return nil, errors.Wrap(err, "error signing payload")
	}

	_, err = armorWriter.Write(payload)
	if err != nil {
		return nil, errors.Wrap(err, "error writing payload to armor writer")
	}

	// The payload is not signed until the armor writer is closed. This will
	// call Signature.Sign to sign the payload.
	armorWriter.Close()
	// The CRC checksum is not written until the armor buffer is closed.
	armorBuffer.Close()
	return &Attestation{
		PublicKeyID: s.publicKeyID,
		Signature:   signature.Bytes(),
	}, nil
}
<commit_msg>Address round 2 comments<commit_after>/*
Copyright 2020 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    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 cryptolib

import (
	"bytes"
	"fmt"
	"io/ioutil"

	"github.com/pkg/errors"
	"golang.org/x/crypto/openpgp"
	"golang.org/x/crypto/openpgp/armor"
)

type pgpVerifierImpl struct{}

// verifyPgp verifies a PGP signature using a public key and outputs the
// payload that was signed. `signature` is an ASCII-armored "attached"
// signature, generated by `gpg --armor --sign --output signature payload`.
// `publicKey` is an ASCII-armored PGP key.
func (v pgpVerifierImpl) verifyPgp(signature, publicKey []byte) ([]byte, error) {
	keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(publicKey))
	if err != nil {
		return nil, errors.Wrap(err, "error reading armored key ring")
	}

	armorBlock, err := armor.Decode(bytes.NewReader(signature))
	if err != nil {
		return nil, errors.Wrap(err, "error decoding armored signature")
	}

	messageDetails, err := openpgp.ReadMessage(armorBlock.Body, keyring, nil, nil)
	if err != nil {
		return nil, errors.Wrap(err, "error reading armor signature")
	}

	// MessageDetails.UnverifiedBody signature is not verified until we read it.
	// This will call PublicKey.VerifySignature for the keys in the keyring.
	payload, err := ioutil.ReadAll(messageDetails.UnverifiedBody)
	if err != nil {
		return nil, errors.Wrap(err, "error reading message contents")
	}

	// Make sure after reading the UnverifiedBody above that the Signature
	// exists and there is no SignatureError.
	if messageDetails.SignatureError != nil {
		return nil, errors.Wrap(messageDetails.SignatureError, "failed to validate: signature error")
	}
	if messageDetails.Signature == nil {
		return nil, fmt.Errorf("failed to validate: signature missing")
	}
	return payload, nil
}

type pgpSigner struct {
	privateKey  *openpgp.Entity
	publicKeyID string
}

// NewPgpSigner creates a Signer interface for PGP Attestations. `privateKey`
// contains the ASCII-armored private key.
func NewPgpSigner(privateKey []byte) (Signer, error) {
	keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(privateKey))
	if err != nil {
		return nil, errors.Wrap(err, "error reading armored private key")
	}
	if len(keyring) != 1 {
		return nil, fmt.Errorf("expected 1 key in keyring, got %d", len(keyring))
	}
	key := keyring[0]
	return &pgpSigner{
		privateKey:  key,
		publicKeyID: fmt.Sprintf("%X", key.PrimaryKey.Fingerprint),
	}, nil
}

// CreateAttestation creates a signed PGP Attestation. The Attestation's
// publicKeyID will be derived from the private key. See Signer for more
// details.
func (s *pgpSigner) CreateAttestation(payload []byte) (*Attestation, error) {
	// Create a buffer to store the signature
	armoredSignature := bytes.Buffer{}

	// Armor-encode the signature before writing to the buffer
	armorWriter, err := armor.Encode(&armoredSignature, openpgp.SignatureType, nil)
	if err != nil {
		return nil, errors.Wrap(err, "error creating armor buffer")
	}

	signatureWriter, err := openpgp.Sign(armorWriter, s.privateKey, nil, nil)
	if err != nil {
		return nil, errors.Wrap(err, "error signing payload")
	}

	_, err = signatureWriter.Write(payload)
	if err != nil {
		return nil, errors.Wrap(err, "error writing payload to armor writer")
	}

	// The payload is not signed until the armor writer is closed. This will
	// call Signature.Sign to sign the payload.
	signatureWriter.Close()
	// The CRC checksum is not written until the armor buffer is closed.
	armorWriter.Close()
	return &Attestation{
		PublicKeyID: s.publicKeyID,
		Signature:   armoredSignature.Bytes(),
	}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"log"
	"net/url"
	"strconv"

	"github.com/ptt/pttweb/article"
	"github.com/ptt/pttweb/atomfeed"
	"github.com/ptt/pttweb/cache"
	"github.com/ptt/pttweb/pttbbs"

	"golang.org/x/net/context"
)

const (
	EntryPerPage = 20

	CtxKeyBoardname = `ContextBoardname`
)

type BbsIndexRequest struct {
	Brd  pttbbs.Board
	Page int
}

func (r *BbsIndexRequest) String() string {
	return fmt.Sprintf("pttweb:bbsindex/%v/%v", r.Brd.BrdName, r.Page)
}

func generateBbsIndex(key cache.Key) (cache.Cacheable, error) {
	r := key.(*BbsIndexRequest)
	page := r.Page

	bbsindex := &BbsIndex{
		Board:   r.Brd,
		IsValid: true,
	}

	// Handle paging
	paging := NewPaging(EntryPerPage, r.Brd.NumPosts)
	if page == 0 {
		page = paging.LastPageNo()
		paging.SetPageNo(page)
	} else if err := paging.SetPageNo(page); err != nil {
		return nil, err
	}

	// Fetch article list
	var err error
	bbsindex.Articles, err = ptt.GetArticleList(r.Brd.Ref(), paging.Cursor(), EntryPerPage)
	if err != nil {
		return nil, err
	}

	// Fetch bottoms when at last page
	if page == paging.LastPageNo() {
		bbsindex.Bottoms, err = ptt.GetBottomList(r.Brd.Ref())
		if err != nil {
			return nil, err
		}
	}

	// Page links
	if u, err := router.Get("bbsindex").URLPath("brdname", r.Brd.BrdName); err == nil {
		bbsindex.LastPage = u.String()
	}
	pageLink := func(n int) string {
		u, err := router.Get("bbsindex_page").URLPath("brdname", r.Brd.BrdName, "page", strconv.Itoa(n))
		if err != nil {
			return ""
		}
		return u.String()
	}
	bbsindex.FirstPage = pageLink(1)
	if page > 1 {
		bbsindex.PrevPage = pageLink(page - 1)
	}
	if page < paging.LastPageNo() {
		bbsindex.NextPage = pageLink(page + 1)
	}

	return bbsindex, nil
}

type BbsSearchRequest struct {
	Brd   pttbbs.Board
	Page  int
	Query string
	Preds []pttbbs.SearchPredicate
}

func (r *BbsSearchRequest) String() string {
	return fmt.Sprintf("pttweb:bbssearch/%v/%v/%v", r.Brd.BrdName, r.Page, r.Query)
}

func generateBbsSearch(key cache.Key) (cache.Cacheable, error) {
	r := key.(*BbsSearchRequest)
	page := r.Page
	if page == 0 {
		page = 1
	}
	offset := -EntryPerPage * page

	bbsindex := &BbsIndex{
		Board:   r.Brd,
		Query:   r.Query,
		IsValid: true,
	}

	// Search articles
	articles, totalPosts, err := pttSearch.Search(r.Brd.Ref(), r.Preds, offset, EntryPerPage)
	if err != nil {
		return nil, err
	}

	// Handle paging
	paging := NewPaging(EntryPerPage, totalPosts)
	if lastPage := paging.LastPageNo(); page > lastPage {
		articles = nil
		bbsindex.IsValid = false
	} else if page == lastPage {
		// We may get extra entries for last page.
		n := totalPosts % EntryPerPage
		if n < len(articles) {
			articles = articles[:n]
		}
	}

	// Show the page in reverse order.
	for i, j := 0, len(articles)-1; i < j; i, j = i+1, j-1 {
		articles[i], articles[j] = articles[j], articles[i]
	}
	bbsindex.Articles = articles

	// Page links, in newest first order.
	pageLink := func(n int) string {
		u, err := router.Get("bbssearch").URLPath("brdname", r.Brd.BrdName)
		if err != nil {
			return ""
		}
		q := url.Values{}
		q.Set("q", r.Query)
		q.Set("page", strconv.Itoa(n))
		u.RawQuery = q.Encode()
		return u.String()
	}
	bbsindex.FirstPage = pageLink(paging.LastPageNo())
	bbsindex.LastPage = pageLink(1)
	if page > 1 {
		bbsindex.NextPage = pageLink(page - 1)
	}
	if page < paging.LastPageNo() {
		bbsindex.PrevPage = pageLink(page + 1)
	}

	return bbsindex, nil
}

type BoardAtomFeedRequest struct {
	Brd pttbbs.Board
}

func (r *BoardAtomFeedRequest) String() string {
	return fmt.Sprintf("pttweb:atomfeed/%v", r.Brd.BrdName)
}

func generateBoardAtomFeed(key cache.Key) (cache.Cacheable, error) {
	r := key.(*BoardAtomFeedRequest)

	if atomConverter == nil {
		return nil, errors.New("atom feed not configured")
	}

	// Fetch article list
	articles, err := ptt.GetArticleList(r.Brd.Ref(), -EntryPerPage, EntryPerPage)
	if err != nil {
		return nil, err
	}
	// Fetch snippets and contruct posts.
	var posts []*atomfeed.PostEntry
	for _, article := range articles {
		// Use an empty string when error.
		snippet, _ := getArticleSnippet(r.Brd, article.FileName)
		posts = append(posts, &atomfeed.PostEntry{
			Article: article,
			Snippet: snippet,
		})
	}

	feed, err := atomConverter.Convert(r.Brd, posts)
	if err != nil {
		log.Println("atomfeed: Convert:", err)
		// Don't return error but cache that it's invalid.
	}
	return &BoardAtomFeed{
		Feed:    feed,
		IsValid: err == nil,
	}, nil
}

const SnippetHeadSize = 16 * 1024 // Enough for 8 pages of 80x24.

func getArticleSnippet(brd pttbbs.Board, filename string) (string, error) {
	p, err := ptt.GetArticleSelect(brd.Ref(), pttbbs.SelectHead, filename, "", 0, SnippetHeadSize)
	if err != nil {
		return "", err
	}
	if len(p.Content) == 0 {
		return "", pttbbs.ErrNotFound
	}

	ra, err := article.Render(article.WithContent(p.Content))
	if err != nil {
		return "", err
	}
	return ra.PreviewContent(), nil
}

const (
	TruncateSize    = 1048576
	TruncateMaxScan = 1024

	HeadSize = 100 * 1024
	TailSize = 50 * 1024
)

type ArticleRequest struct {
	Namespace string
	Brd       pttbbs.Board
	Filename  string
	Select    func(m pttbbs.SelectMethod, offset, maxlen int) (*pttbbs.ArticlePart, error)
}

func (r *ArticleRequest) String() string {
	return fmt.Sprintf("pttweb:%v/%v/%v", r.Namespace, r.Brd.BrdName, r.Filename)
}

func (r *ArticleRequest) Boardname() string {
	return r.Brd.BrdName
}

func generateArticle(key cache.Key) (cache.Cacheable, error) {
	r := key.(*ArticleRequest)
	ctx := context.WithValue(context.TODO(), CtxKeyBoardname, r)

	p, err := r.Select(pttbbs.SelectHead, 0, HeadSize)
	if err != nil {
		return nil, err
	}

	// We don't want head and tail have duplicate content
	if p.FileSize > HeadSize && p.FileSize <= HeadSize+TailSize {
		p, err = r.Select(pttbbs.SelectPart, 0, p.FileSize)
		if err != nil {
			return nil, err
		}
	}

	if len(p.Content) == 0 {
		return nil, pttbbs.ErrNotFound
	}

	a := new(Article)

	a.IsPartial = p.Length < p.FileSize
	a.IsTruncated = a.IsPartial

	if a.IsPartial {
		// Get and render tail
		ptail, err := r.Select(pttbbs.SelectTail, -TailSize, TailSize)
		if err != nil {
			return nil, err
		}
		if len(ptail.Content) > 0 {
			ra, err := article.Render(
				article.WithContent(ptail.Content),
				article.WithContext(ctx),
				article.WithDisableArticleHeader(),
			)
			if err != nil {
				return nil, err
			}
			a.ContentTailHtml = ra.HTML()
		}
		a.CacheKey = ptail.CacheKey
		a.NextOffset = ptail.FileSize - TailSize + ptail.Offset + ptail.Length
	} else {
		a.CacheKey = p.CacheKey
		a.NextOffset = p.Length
	}

	ra, err := article.Render(
		article.WithContent(p.Content),
		article.WithContext(ctx),
	)
	if err != nil {
		return nil, err
	}
	a.ParsedTitle = ra.ParsedTitle()
	a.PreviewContent = ra.PreviewContent()
	a.ContentHtml = ra.HTML()
	a.IsValid = true
	return a, nil
}

type ArticlePartRequest struct {
	Brd      pttbbs.Board
	Filename string
	CacheKey string
	Offset   int
}

func (r *ArticlePartRequest) String() string {
	return fmt.Sprintf("pttweb:bbs/%v/%v#%v,%v", r.Brd.BrdName, r.Filename, r.CacheKey, r.Offset)
}

func (r *ArticlePartRequest) Boardname() string {
	return r.Brd.BrdName
}

func generateArticlePart(key cache.Key) (cache.Cacheable, error) {
	r := key.(*ArticlePartRequest)
	ctx := context.WithValue(context.TODO(), CtxKeyBoardname, r)

	p, err := ptt.GetArticleSelect(r.Brd.Ref(), pttbbs.SelectHead, r.Filename, r.CacheKey, r.Offset, -1)
	if err == pttbbs.ErrNotFound {
		// Returns an invalid result
		return new(ArticlePart), nil
	}
	if err != nil {
		return nil, err
	}

	ap := new(ArticlePart)
	ap.IsValid = true
	ap.CacheKey = p.CacheKey
	ap.NextOffset = r.Offset + p.Offset + p.Length

	if len(p.Content) > 0 {
		ra, err := article.Render(
			article.WithContent(p.Content),
			article.WithContext(ctx),
			article.WithDisableArticleHeader(),
		)
		if err != nil {
			return nil, err
		}
		ap.ContentHtml = string(ra.HTML())
	}

	return ap, nil
}

func truncateLargeContent(content []byte, size, maxScan int) []byte {
	if len(content) <= size {
		return content
	}
	for i := size - 1; i >= size-maxScan && i >= 0; i-- {
		if content[i] == '\n' {
			return content[:i+1]
		}
	}
	return content[:size]
}
<commit_msg>Change query part of memcache key to base64(sha256(query)).<commit_after>package main

import (
	"crypto/sha256"
	"encoding/base64"
	"errors"
	"fmt"
	"log"
	"net/url"
	"strconv"

	"github.com/ptt/pttweb/article"
	"github.com/ptt/pttweb/atomfeed"
	"github.com/ptt/pttweb/cache"
	"github.com/ptt/pttweb/pttbbs"

	"golang.org/x/net/context"
)

const (
	EntryPerPage = 20

	CtxKeyBoardname = `ContextBoardname`
)

type BbsIndexRequest struct {
	Brd  pttbbs.Board
	Page int
}

func (r *BbsIndexRequest) String() string {
	return fmt.Sprintf("pttweb:bbsindex/%v/%v", r.Brd.BrdName, r.Page)
}

func generateBbsIndex(key cache.Key) (cache.Cacheable, error) {
	r := key.(*BbsIndexRequest)
	page := r.Page

	bbsindex := &BbsIndex{
		Board:   r.Brd,
		IsValid: true,
	}

	// Handle paging
	paging := NewPaging(EntryPerPage, r.Brd.NumPosts)
	if page == 0 {
		page = paging.LastPageNo()
		paging.SetPageNo(page)
	} else if err := paging.SetPageNo(page); err != nil {
		return nil, err
	}

	// Fetch article list
	var err error
	bbsindex.Articles, err = ptt.GetArticleList(r.Brd.Ref(), paging.Cursor(), EntryPerPage)
	if err != nil {
		return nil, err
	}

	// Fetch bottoms when at last page
	if page == paging.LastPageNo() {
		bbsindex.Bottoms, err = ptt.GetBottomList(r.Brd.Ref())
		if err != nil {
			return nil, err
		}
	}

	// Page links
	if u, err := router.Get("bbsindex").URLPath("brdname", r.Brd.BrdName); err == nil {
		bbsindex.LastPage = u.String()
	}
	pageLink := func(n int) string {
		u, err := router.Get("bbsindex_page").URLPath("brdname", r.Brd.BrdName, "page", strconv.Itoa(n))
		if err != nil {
			return ""
		}
		return u.String()
	}
	bbsindex.FirstPage = pageLink(1)
	if page > 1 {
		bbsindex.PrevPage = pageLink(page - 1)
	}
	if page < paging.LastPageNo() {
		bbsindex.NextPage = pageLink(page + 1)
	}

	return bbsindex, nil
}

type BbsSearchRequest struct {
	Brd   pttbbs.Board
	Page  int
	Query string
	Preds []pttbbs.SearchPredicate
}

func (r *BbsSearchRequest) String() string {
	queryHash := sha256.Sum256([]byte(r.Query))
	query := base64.URLEncoding.EncodeToString(queryHash[:])
	return fmt.Sprintf("pttweb:bbssearch/%v/%v/%v", r.Brd.BrdName, r.Page, query)
}

func generateBbsSearch(key cache.Key) (cache.Cacheable, error) {
	r := key.(*BbsSearchRequest)
	page := r.Page
	if page == 0 {
		page = 1
	}
	offset := -EntryPerPage * page

	bbsindex := &BbsIndex{
		Board:   r.Brd,
		Query:   r.Query,
		IsValid: true,
	}

	// Search articles
	articles, totalPosts, err := pttSearch.Search(r.Brd.Ref(), r.Preds, offset, EntryPerPage)
	if err != nil {
		return nil, err
	}

	// Handle paging
	paging := NewPaging(EntryPerPage, totalPosts)
	if lastPage := paging.LastPageNo(); page > lastPage {
		articles = nil
		bbsindex.IsValid = false
	} else if page == lastPage {
		// We may get extra entries for last page.
		n := totalPosts % EntryPerPage
		if n < len(articles) {
			articles = articles[:n]
		}
	}

	// Show the page in reverse order.
	for i, j := 0, len(articles)-1; i < j; i, j = i+1, j-1 {
		articles[i], articles[j] = articles[j], articles[i]
	}
	bbsindex.Articles = articles

	// Page links, in newest first order.
	pageLink := func(n int) string {
		u, err := router.Get("bbssearch").URLPath("brdname", r.Brd.BrdName)
		if err != nil {
			return ""
		}
		q := url.Values{}
		q.Set("q", r.Query)
		q.Set("page", strconv.Itoa(n))
		u.RawQuery = q.Encode()
		return u.String()
	}
	bbsindex.FirstPage = pageLink(paging.LastPageNo())
	bbsindex.LastPage = pageLink(1)
	if page > 1 {
		bbsindex.NextPage = pageLink(page - 1)
	}
	if page < paging.LastPageNo() {
		bbsindex.PrevPage = pageLink(page + 1)
	}

	return bbsindex, nil
}

type BoardAtomFeedRequest struct {
	Brd pttbbs.Board
}

func (r *BoardAtomFeedRequest) String() string {
	return fmt.Sprintf("pttweb:atomfeed/%v", r.Brd.BrdName)
}

func generateBoardAtomFeed(key cache.Key) (cache.Cacheable, error) {
	r := key.(*BoardAtomFeedRequest)

	if atomConverter == nil {
		return nil, errors.New("atom feed not configured")
	}

	// Fetch article list
	articles, err := ptt.GetArticleList(r.Brd.Ref(), -EntryPerPage, EntryPerPage)
	if err != nil {
		return nil, err
	}
	// Fetch snippets and contruct posts.
	var posts []*atomfeed.PostEntry
	for _, article := range articles {
		// Use an empty string when error.
		snippet, _ := getArticleSnippet(r.Brd, article.FileName)
		posts = append(posts, &atomfeed.PostEntry{
			Article: article,
			Snippet: snippet,
		})
	}

	feed, err := atomConverter.Convert(r.Brd, posts)
	if err != nil {
		log.Println("atomfeed: Convert:", err)
		// Don't return error but cache that it's invalid.
	}
	return &BoardAtomFeed{
		Feed:    feed,
		IsValid: err == nil,
	}, nil
}

const SnippetHeadSize = 16 * 1024 // Enough for 8 pages of 80x24.

func getArticleSnippet(brd pttbbs.Board, filename string) (string, error) {
	p, err := ptt.GetArticleSelect(brd.Ref(), pttbbs.SelectHead, filename, "", 0, SnippetHeadSize)
	if err != nil {
		return "", err
	}
	if len(p.Content) == 0 {
		return "", pttbbs.ErrNotFound
	}

	ra, err := article.Render(article.WithContent(p.Content))
	if err != nil {
		return "", err
	}
	return ra.PreviewContent(), nil
}

const (
	TruncateSize    = 1048576
	TruncateMaxScan = 1024

	HeadSize = 100 * 1024
	TailSize = 50 * 1024
)

type ArticleRequest struct {
	Namespace string
	Brd       pttbbs.Board
	Filename  string
	Select    func(m pttbbs.SelectMethod, offset, maxlen int) (*pttbbs.ArticlePart, error)
}

func (r *ArticleRequest) String() string {
	return fmt.Sprintf("pttweb:%v/%v/%v", r.Namespace, r.Brd.BrdName, r.Filename)
}

func (r *ArticleRequest) Boardname() string {
	return r.Brd.BrdName
}

func generateArticle(key cache.Key) (cache.Cacheable, error) {
	r := key.(*ArticleRequest)
	ctx := context.WithValue(context.TODO(), CtxKeyBoardname, r)

	p, err := r.Select(pttbbs.SelectHead, 0, HeadSize)
	if err != nil {
		return nil, err
	}

	// We don't want head and tail have duplicate content
	if p.FileSize > HeadSize && p.FileSize <= HeadSize+TailSize {
		p, err = r.Select(pttbbs.SelectPart, 0, p.FileSize)
		if err != nil {
			return nil, err
		}
	}

	if len(p.Content) == 0 {
		return nil, pttbbs.ErrNotFound
	}

	a := new(Article)

	a.IsPartial = p.Length < p.FileSize
	a.IsTruncated = a.IsPartial

	if a.IsPartial {
		// Get and render tail
		ptail, err := r.Select(pttbbs.SelectTail, -TailSize, TailSize)
		if err != nil {
			return nil, err
		}
		if len(ptail.Content) > 0 {
			ra, err := article.Render(
				article.WithContent(ptail.Content),
				article.WithContext(ctx),
				article.WithDisableArticleHeader(),
			)
			if err != nil {
				return nil, err
			}
			a.ContentTailHtml = ra.HTML()
		}
		a.CacheKey = ptail.CacheKey
		a.NextOffset = ptail.FileSize - TailSize + ptail.Offset + ptail.Length
	} else {
		a.CacheKey = p.CacheKey
		a.NextOffset = p.Length
	}

	ra, err := article.Render(
		article.WithContent(p.Content),
		article.WithContext(ctx),
	)
	if err != nil {
		return nil, err
	}
	a.ParsedTitle = ra.ParsedTitle()
	a.PreviewContent = ra.PreviewContent()
	a.ContentHtml = ra.HTML()
	a.IsValid = true
	return a, nil
}

type ArticlePartRequest struct {
	Brd      pttbbs.Board
	Filename string
	CacheKey string
	Offset   int
}

func (r *ArticlePartRequest) String() string {
	return fmt.Sprintf("pttweb:bbs/%v/%v#%v,%v", r.Brd.BrdName, r.Filename, r.CacheKey, r.Offset)
}

func (r *ArticlePartRequest) Boardname() string {
	return r.Brd.BrdName
}

func generateArticlePart(key cache.Key) (cache.Cacheable, error) {
	r := key.(*ArticlePartRequest)
	ctx := context.WithValue(context.TODO(), CtxKeyBoardname, r)

	p, err := ptt.GetArticleSelect(r.Brd.Ref(), pttbbs.SelectHead, r.Filename, r.CacheKey, r.Offset, -1)
	if err == pttbbs.ErrNotFound {
		// Returns an invalid result
		return new(ArticlePart), nil
	}
	if err != nil {
		return nil, err
	}

	ap := new(ArticlePart)
	ap.IsValid = true
	ap.CacheKey = p.CacheKey
	ap.NextOffset = r.Offset + p.Offset + p.Length

	if len(p.Content) > 0 {
		ra, err := article.Render(
			article.WithContent(p.Content),
			article.WithContext(ctx),
			article.WithDisableArticleHeader(),
		)
		if err != nil {
			return nil, err
		}
		ap.ContentHtml = string(ra.HTML())
	}

	return ap, nil
}

func truncateLargeContent(content []byte, size, maxScan int) []byte {
	if len(content) <= size {
		return content
	}
	for i := size - 1; i >= size-maxScan && i >= 0; i-- {
		if content[i] == '\n' {
			return content[:i+1]
		}
	}
	return content[:size]
}
<|endoftext|>


<commit_before>package cli

import (
	"flag"

	"github.com/cloudflare/cfssl/config"
	"github.com/cloudflare/cfssl/helpers"
	"github.com/cloudflare/cfssl/signer/pkcs11"
	"github.com/cloudflare/cfssl/signer/universal"
)

// Config is a type to hold flag values used by cfssl commands.
type Config struct {
	Hostname          string
	CertFile          string
	CSRFile           string
	CAFile            string
	CAKeyFile         string
	KeyFile           string
	IntermediatesFile string
	CABundleFile      string
	IntBundleFile     string
	Address           string
	Port              int
	Password          string
	ConfigFile        string
	CFG               *config.Config
	Profile           string
	IsCA              bool
	IntDir            string
	Flavor            string
	Metadata          string
	Domain            string
	IP                string
	Remote            string
	Label             string
	AuthKey           string
	Module            string
	Token             string
	PIN               string
	PKCS11Label       string
	ResponderFile     string
	Status            string
	Reason            int
	RevokedAt         string
	Interval          int64
	List              bool
	Family            string
	Scanner           string
	Responses         string
	Path              string
	UseLocal          bool
}

// registerFlags defines all cfssl command flags and associates their values with variables.
func registerFlags(c *Config, f *flag.FlagSet) {
	f.StringVar(&c.Hostname, "hostname", "", "Hostname for the cert, could be a comma-separated hostname list")
	f.StringVar(&c.CertFile, "cert", "", "Client certificate that contains the public key")
	f.StringVar(&c.CSRFile, "csr", "", "Certificate signature request file for new public key")
	f.StringVar(&c.CAFile, "ca", "ca.pem", "CA used to sign the new certificate")
	f.StringVar(&c.CAKeyFile, "ca-key", "ca-key.pem", "CA private key")
	f.StringVar(&c.KeyFile, "key", "", "private key for the certificate")
	f.StringVar(&c.IntermediatesFile, "intermediates", "", "intermediate certs")
	f.StringVar(&c.CABundleFile, "ca-bundle", "/etc/cfssl/ca-bundle.crt", "Bundle to be used for root certificates pool")
	f.StringVar(&c.IntBundleFile, "int-bundle", "/etc/cfssl/int-bundle.crt", "Bundle to be used for intermediate certificates pool")
	f.StringVar(&c.Address, "address", "127.0.0.1", "Address to bind")
	f.IntVar(&c.Port, "port", 8888, "Port to bind")
	f.StringVar(&c.ConfigFile, "config", "", "path to configuration file")
	f.StringVar(&c.Profile, "profile", "", "signing profile to use")
	f.BoolVar(&c.IsCA, "initca", false, "initialise new CA")
	f.StringVar(&c.IntDir, "int-dir", "/etc/cfssl/intermediates", "specify intermediates directory")
	f.StringVar(&c.Flavor, "flavor", "ubiquitous", "Bundle Flavor: ubiquitous, optimal and force.")
	f.StringVar(&c.Metadata, "metadata", "/etc/cfssl/ca-bundle.crt.metadata", "Metadata file for root certificate presence. The content of the file is a json dictionary (k,v): each key k is SHA-1 digest of a root certificate while value v is a list of key store filenames.")
	f.StringVar(&c.Domain, "domain", "", "remote server domain name")
	f.StringVar(&c.IP, "ip", "", "remote server ip")
	f.StringVar(&c.Remote, "remote", "", "remote CFSSL server")
	f.StringVar(&c.Label, "label", "", "key label to use in remote CFSSL server")
	f.StringVar(&c.AuthKey, "authkey", "", "key to authenticate requests to remote CFSSL server")
	f.StringVar(&c.ResponderFile, "responder", "", "Certificate for OCSP responder")
	f.StringVar(&c.Status, "status", "good", "Status of the certificate: good, revoked, unknown")
	f.IntVar(&c.Reason, "reason", 0, "Reason code for revocation")
	f.StringVar(&c.RevokedAt, "revoked-at", "now", "Date of revocation (YYYY-MM-DD)")
	f.Int64Var(&c.Interval, "interval", int64(4*helpers.OneDay), "Interval between OCSP updates, in seconds (default: 4 days)")
	f.BoolVar(&c.List, "list", false, "list possible scanners")
	f.StringVar(&c.Family, "family", "", "scanner family regular expression")
	f.StringVar(&c.Scanner, "scanner", "", "scanner regular expression")
	f.StringVar(&c.Responses, "responses", "", "file to load OCSP responses from")
	f.StringVar(&c.Path, "path", "/", "Path on which the server will listen")
	f.StringVar(&c.Password, "password", "", "Password for accessing PKCS #12 data passed to bundler")
	f.BoolVar(&c.UseLocal, "uselocal", false, "serve local static files as opposed to compiled ones")

	if pkcs11.Enabled {
		f.StringVar(&c.Module, "pkcs11-module", "", "PKCS #11 module")
		f.StringVar(&c.Token, "pkcs11-token", "", "PKCS #11 token")
		f.StringVar(&c.PIN, "pkcs11-pin", "", "PKCS #11 user PIN")
		f.StringVar(&c.PKCS11Label, "pkcs11-label", "", "PKCS #11 label")
	}
}

// RootFromConfig returns a universal signer Root structure that can
// be used to produce a signer.
func RootFromConfig(c *Config) universal.Root {
	return universal.Root{
		Config: map[string]string{
			"pkcs11-module":   c.Module,
			"pkcs11-token":    c.Token,
			"pkcs11-label":    c.PKCS11Label,
			"pkcs11-user-pin": c.PIN,
			"cert-file":       c.CAFile,
			"key-file":        c.CAKeyFile,
		},
		ForceRemote: c.Remote != "",
	}
}
<commit_msg>Set pkcs11 user pin in environment<commit_after>package cli

import (
	"flag"
	"os"

	"github.com/cloudflare/cfssl/config"
	"github.com/cloudflare/cfssl/helpers"
	"github.com/cloudflare/cfssl/signer/pkcs11"
	"github.com/cloudflare/cfssl/signer/universal"
)

// Config is a type to hold flag values used by cfssl commands.
type Config struct {
	Hostname          string
	CertFile          string
	CSRFile           string
	CAFile            string
	CAKeyFile         string
	KeyFile           string
	IntermediatesFile string
	CABundleFile      string
	IntBundleFile     string
	Address           string
	Port              int
	Password          string
	ConfigFile        string
	CFG               *config.Config
	Profile           string
	IsCA              bool
	IntDir            string
	Flavor            string
	Metadata          string
	Domain            string
	IP                string
	Remote            string
	Label             string
	AuthKey           string
	Module            string
	Token             string
	PIN               string
	PKCS11Label       string
	ResponderFile     string
	Status            string
	Reason            int
	RevokedAt         string
	Interval          int64
	List              bool
	Family            string
	Scanner           string
	Responses         string
	Path              string
	UseLocal          bool
}

// registerFlags defines all cfssl command flags and associates their values with variables.
func registerFlags(c *Config, f *flag.FlagSet) {
	f.StringVar(&c.Hostname, "hostname", "", "Hostname for the cert, could be a comma-separated hostname list")
	f.StringVar(&c.CertFile, "cert", "", "Client certificate that contains the public key")
	f.StringVar(&c.CSRFile, "csr", "", "Certificate signature request file for new public key")
	f.StringVar(&c.CAFile, "ca", "ca.pem", "CA used to sign the new certificate")
	f.StringVar(&c.CAKeyFile, "ca-key", "ca-key.pem", "CA private key")
	f.StringVar(&c.KeyFile, "key", "", "private key for the certificate")
	f.StringVar(&c.IntermediatesFile, "intermediates", "", "intermediate certs")
	f.StringVar(&c.CABundleFile, "ca-bundle", "/etc/cfssl/ca-bundle.crt", "Bundle to be used for root certificates pool")
	f.StringVar(&c.IntBundleFile, "int-bundle", "/etc/cfssl/int-bundle.crt", "Bundle to be used for intermediate certificates pool")
	f.StringVar(&c.Address, "address", "127.0.0.1", "Address to bind")
	f.IntVar(&c.Port, "port", 8888, "Port to bind")
	f.StringVar(&c.ConfigFile, "config", "", "path to configuration file")
	f.StringVar(&c.Profile, "profile", "", "signing profile to use")
	f.BoolVar(&c.IsCA, "initca", false, "initialise new CA")
	f.StringVar(&c.IntDir, "int-dir", "/etc/cfssl/intermediates", "specify intermediates directory")
	f.StringVar(&c.Flavor, "flavor", "ubiquitous", "Bundle Flavor: ubiquitous, optimal and force.")
	f.StringVar(&c.Metadata, "metadata", "/etc/cfssl/ca-bundle.crt.metadata", "Metadata file for root certificate presence. The content of the file is a json dictionary (k,v): each key k is SHA-1 digest of a root certificate while value v is a list of key store filenames.")
	f.StringVar(&c.Domain, "domain", "", "remote server domain name")
	f.StringVar(&c.IP, "ip", "", "remote server ip")
	f.StringVar(&c.Remote, "remote", "", "remote CFSSL server")
	f.StringVar(&c.Label, "label", "", "key label to use in remote CFSSL server")
	f.StringVar(&c.AuthKey, "authkey", "", "key to authenticate requests to remote CFSSL server")
	f.StringVar(&c.ResponderFile, "responder", "", "Certificate for OCSP responder")
	f.StringVar(&c.Status, "status", "good", "Status of the certificate: good, revoked, unknown")
	f.IntVar(&c.Reason, "reason", 0, "Reason code for revocation")
	f.StringVar(&c.RevokedAt, "revoked-at", "now", "Date of revocation (YYYY-MM-DD)")
	f.Int64Var(&c.Interval, "interval", int64(4*helpers.OneDay), "Interval between OCSP updates, in seconds (default: 4 days)")
	f.BoolVar(&c.List, "list", false, "list possible scanners")
	f.StringVar(&c.Family, "family", "", "scanner family regular expression")
	f.StringVar(&c.Scanner, "scanner", "", "scanner regular expression")
	f.StringVar(&c.Responses, "responses", "", "file to load OCSP responses from")
	f.StringVar(&c.Path, "path", "/", "Path on which the server will listen")
	f.StringVar(&c.Password, "password", "", "Password for accessing PKCS #12 data passed to bundler")
	f.BoolVar(&c.UseLocal, "uselocal", false, "serve local static files as opposed to compiled ones")

	if pkcs11.Enabled {
		f.StringVar(&c.Module, "pkcs11-module", "", "PKCS #11 module")
		f.StringVar(&c.Token, "pkcs11-token", "", "PKCS #11 token")
		f.StringVar(&c.PIN, "pkcs11-pin", os.Getenv("USER_PIN"), "PKCS #11 user PIN")
		f.StringVar(&c.PKCS11Label, "pkcs11-label", "", "PKCS #11 label")
	}
}

// RootFromConfig returns a universal signer Root structure that can
// be used to produce a signer.
func RootFromConfig(c *Config) universal.Root {
	return universal.Root{
		Config: map[string]string{
			"pkcs11-module":   c.Module,
			"pkcs11-token":    c.Token,
			"pkcs11-label":    c.PKCS11Label,
			"pkcs11-user-pin": c.PIN,
			"cert-file":       c.CAFile,
			"key-file":        c.CAKeyFile,
		},
		ForceRemote: c.Remote != "",
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Scaleway. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.md file.

package cli

import (
	"fmt"
	"io/ioutil"
	"strings"

	"github.com/scaleway/scaleway-cli/pkg/api"
	"github.com/scaleway/scaleway-cli/pkg/scwversion"
)

var cmdUserdata = &Command{
	Exec:        runUserdata,
	UsageLine:   "_userdata [OPTIONS] SERVER [FIELD[=VALUE]]",
	Description: "",
	Hidden:      true,
	Help:        "List, read and write and delete server's userdata",
	Examples: `
    $ scw _userdata myserver
    $ scw _userdata myserver key
    $ scw _userdata myserver key=value
    $ scw _userdata myserver key=""
`,
}

func init() {
	cmdUserdata.Flag.BoolVar(&userdataHelp, []string{"h", "-help"}, false, "Print usage")
}

// Flags
var userdataHelp bool // -h, --help flag

func runUserdata(cmd *Command, args []string) error {
	if userdataHelp {
		return cmd.PrintUsage()
	}
	if len(args) < 1 {
		return cmd.PrintShortUsage()
	}
	metadata := false
	ctx := cmd.GetContext(args)
	var API *api.ScalewayAPI
	var err error
	var serverID string
	if args[0] == "local" {
		API, err = api.NewScalewayAPI("", "", scwversion.UserAgent())
		if err != nil {
			return err
		}
		metadata = true
	} else {
		if ctx.API == nil {
			return fmt.Errorf("You need to login first: 'scw login'")
		}
		serverID, err = ctx.API.GetServerID(args[0])
		if err != nil {
			return err
		}
		API = ctx.API
	}

	switch len(args) {
	case 1:
		// List userdata
		res, err := API.GetUserdatas(serverID, metadata)
		if err != nil {
			return err
		}
		for _, key := range res.UserData {
			fmt.Fprintln(ctx.Stdout, key)
		}
	default:
		parts := strings.Split(args[1], "=")
		key := parts[0]
		switch len(parts) {
		case 1:
			// Get userdatas
			res, err := API.GetUserdata(serverID, key, metadata)
			if err != nil {
				return err
			}
			fmt.Fprintf(ctx.Stdout, "%s\n", res.String())
		default:
			value := args[1][len(parts[0])+1:]
			if value != "" {
				var data []byte
				// Set userdata
				if value[0] == '@' {
					data, err = ioutil.ReadFile(value[1:])
					if err != nil {
						return err
					}
				} else {
					data = []byte(value)
				}
				err := API.PatchUserdata(serverID, key, data, metadata)
				if err != nil {
					return err
				}
				fmt.Fprintln(ctx.Stdout, key)
			} else {
				// Delete userdata
				err := API.DeleteUserdata(serverID, key, metadata)
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}
<commit_msg>_userdata: handles USERDATA=@~/path/to/file<commit_after>// Copyright (C) 2015 Scaleway. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.md file.

package cli

import (
	"fmt"
	"io/ioutil"
	"strings"

	"github.com/scaleway/scaleway-cli/pkg/api"
	"github.com/scaleway/scaleway-cli/pkg/config"
	"github.com/scaleway/scaleway-cli/pkg/scwversion"
)

var cmdUserdata = &Command{
	Exec:        runUserdata,
	UsageLine:   "_userdata [OPTIONS] SERVER [FIELD[=VALUE]]",
	Description: "",
	Hidden:      true,
	Help:        "List, read and write and delete server's userdata",
	Examples: `
    $ scw _userdata myserver
    $ scw _userdata myserver key
    $ scw _userdata myserver key=value
    $ scw _userdata myserver key=""
`,
}

func init() {
	cmdUserdata.Flag.BoolVar(&userdataHelp, []string{"h", "-help"}, false, "Print usage")
}

// Flags
var userdataHelp bool // -h, --help flag

func runUserdata(cmd *Command, args []string) error {
	if userdataHelp {
		return cmd.PrintUsage()
	}
	if len(args) < 1 {
		return cmd.PrintShortUsage()
	}
	metadata := false
	ctx := cmd.GetContext(args)
	var API *api.ScalewayAPI
	var err error
	var serverID string
	if args[0] == "local" {
		API, err = api.NewScalewayAPI("", "", scwversion.UserAgent())
		if err != nil {
			return err
		}
		metadata = true
	} else {
		if ctx.API == nil {
			return fmt.Errorf("You need to login first: 'scw login'")
		}
		serverID, err = ctx.API.GetServerID(args[0])
		if err != nil {
			return err
		}
		API = ctx.API
	}

	switch len(args) {
	case 1:
		// List userdata
		res, err := API.GetUserdatas(serverID, metadata)
		if err != nil {
			return err
		}
		for _, key := range res.UserData {
			fmt.Fprintln(ctx.Stdout, key)
		}
	default:
		parts := strings.Split(args[1], "=")
		key := parts[0]
		switch len(parts) {
		case 1:
			// Get userdatas
			res, err := API.GetUserdata(serverID, key, metadata)
			if err != nil {
				return err
			}
			fmt.Fprintf(ctx.Stdout, "%s\n", res.String())
		default:
			value := args[1][len(parts[0])+1:]
			if value != "" {
				var data []byte
				// Set userdata
				if value[0] == '@' {
					if len(value) > 1 && value[1] == '~' {
						home, err := config.GetHomeDir()
						if err != nil {
							return err
						}
						value = "@" + home + value[2:]
					}
					data, err = ioutil.ReadFile(value[1:])
					if err != nil {
						return err
					}
				} else {
					data = []byte(value)
				}
				err := API.PatchUserdata(serverID, key, data, metadata)
				if err != nil {
					return err
				}
				fmt.Fprintln(ctx.Stdout, key)
			} else {
				// Delete userdata
				err := API.DeleteUserdata(serverID, key, metadata)
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package assets

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/yosssi/gcss"
)

// CompileJavascripts compiles a set of JS files into a single large file by
// appending them all to each other. Files are appended in alphabetical order
// so we depend on the fact that there aren't too many interdependencies
// between files. A common requirement can be given an underscore prefix to be
// loaded first.
func CompileJavascripts(inPath, outPath string) error {
	start := time.Now()
	defer func() {
		log.Debugf("Compiled script assets in %v.", time.Now().Sub(start))
	}()

	log.Debugf("Building: %v", outPath)

	javascriptInfos, err := ioutil.ReadDir(inPath)
	if err != nil {
		return err
	}

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

	for _, javascriptInfo := range javascriptInfos {
		if isHidden(javascriptInfo.Name()) {
			continue
		}

		log.Debugf("Including: %v", javascriptInfo.Name())

		inFile, err := os.Open(path.Join(inPath, javascriptInfo.Name()))
		if err != nil {
			return err
		}

		outFile.WriteString("/* " + javascriptInfo.Name() + " */\n\n")
		outFile.WriteString("(function() {\n\n")

		_, err = io.Copy(outFile, inFile)
		if err != nil {
			return err
		}

		outFile.WriteString("\n\n")
		outFile.WriteString("}).call(this);\n\n")
	}

	return nil
}

// CompileStylesheets compiles a set of stylesheet files into a single large
// file by appending them all to each other. Files are appended in alphabetical
// order so we depend on the fact that there aren't too many interdependencies
// between files. CSS reset in particular is given an underscore prefix so that
// it gets to load first.
//
// If a file has a ".sass" suffix, we attempt to render it as GCSS. This isn't
// a perfect symmetry, but works well enough for these cases.
func CompileStylesheets(inPath, outPath string) error {
	start := time.Now()
	defer func() {
		log.Debugf("Compiled stylesheet assets in %v.", time.Now().Sub(start))
	}()

	log.Debugf("Building: %v", outPath)

	stylesheetInfos, err := ioutil.ReadDir(inPath)
	if err != nil {
		return err
	}

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

	for _, stylesheetInfo := range stylesheetInfos {
		if isHidden(stylesheetInfo.Name()) {
			continue
		}

		log.Debugf("Including: %v", stylesheetInfo.Name())

		inFile, err := os.Open(path.Join(inPath, stylesheetInfo.Name()))
		if err != nil {
			return err
		}

		outFile.WriteString("/* " + stylesheetInfo.Name() + " */\n\n")

		if strings.HasSuffix(stylesheetInfo.Name(), ".sass") {
			_, err := gcss.Compile(outFile, inFile)
			if err != nil {
				return fmt.Errorf("Error compiling %v: %v",
					stylesheetInfo.Name(), err)
			}
		} else {
			_, err := io.Copy(outFile, inFile)
			if err != nil {
				return err
			}
		}

		outFile.WriteString("\n\n")
	}

	return nil
}

// Detects a hidden file, i.e. one that starts with a dot.
func isHidden(file string) bool {
	return strings.HasPrefix(file, ".")
}
<commit_msg>Ignore non-JS files files in content/javascripts/<commit_after>package assets

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/yosssi/gcss"
)

// CompileJavascripts compiles a set of JS files into a single large file by
// appending them all to each other. Files are appended in alphabetical order
// so we depend on the fact that there aren't too many interdependencies
// between files. A common requirement can be given an underscore prefix to be
// loaded first.
func CompileJavascripts(inPath, outPath string) error {
	start := time.Now()
	defer func() {
		log.Debugf("Compiled script assets in %v.", time.Now().Sub(start))
	}()

	log.Debugf("Building: %v", outPath)

	javascriptInfos, err := ioutil.ReadDir(inPath)
	if err != nil {
		return err
	}

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

	for _, javascriptInfo := range javascriptInfos {
		if isHidden(javascriptInfo.Name()) {
			continue
		}

		log.Debugf("Including: %v", javascriptInfo.Name())

		inFile, err := os.Open(path.Join(inPath, javascriptInfo.Name()))
		if err != nil {
			return err
		}

		outFile.WriteString("/* " + javascriptInfo.Name() + " */\n\n")
		outFile.WriteString("(function() {\n\n")

		// Ignore non-JS files in the directory (I have a README in there)
		if strings.HasSuffix(javascriptInfo.Name(), ".js") {
			_, err = io.Copy(outFile, inFile)
			if err != nil {
				return err
			}
		}

		outFile.WriteString("\n\n")
		outFile.WriteString("}).call(this);\n\n")
	}

	return nil
}

// CompileStylesheets compiles a set of stylesheet files into a single large
// file by appending them all to each other. Files are appended in alphabetical
// order so we depend on the fact that there aren't too many interdependencies
// between files. CSS reset in particular is given an underscore prefix so that
// it gets to load first.
//
// If a file has a ".sass" suffix, we attempt to render it as GCSS. This isn't
// a perfect symmetry, but works well enough for these cases.
func CompileStylesheets(inPath, outPath string) error {
	start := time.Now()
	defer func() {
		log.Debugf("Compiled stylesheet assets in %v.", time.Now().Sub(start))
	}()

	log.Debugf("Building: %v", outPath)

	stylesheetInfos, err := ioutil.ReadDir(inPath)
	if err != nil {
		return err
	}

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

	for _, stylesheetInfo := range stylesheetInfos {
		if isHidden(stylesheetInfo.Name()) {
			continue
		}

		log.Debugf("Including: %v", stylesheetInfo.Name())

		inFile, err := os.Open(path.Join(inPath, stylesheetInfo.Name()))
		if err != nil {
			return err
		}

		outFile.WriteString("/* " + stylesheetInfo.Name() + " */\n\n")

		if strings.HasSuffix(stylesheetInfo.Name(), ".sass") {
			_, err := gcss.Compile(outFile, inFile)
			if err != nil {
				return fmt.Errorf("Error compiling %v: %v",
					stylesheetInfo.Name(), err)
			}
		} else {
			_, err := io.Copy(outFile, inFile)
			if err != nil {
				return err
			}
		}

		outFile.WriteString("\n\n")
	}

	return nil
}

// Detects a hidden file, i.e. one that starts with a dot.
func isHidden(file string) bool {
	return strings.HasPrefix(file, ".")
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/github/hub/ui"
	"github.com/github/hub/utils"
)

var cmdAlias = &Command{
	Run:   alias,
	Usage: "alias [-s] [<SHELL>]",
	Long: `Show shell instructions for wrapping git.

## Options
	-s
		Output shell script suitable for 'eval'.

	<SHELL>
		Specify the type of shell (default: "$SHELL" environment variable).

## See also:

hub(1)
`,
}

var flagAliasScript bool

func init() {
	cmdAlias.Flag.BoolVarP(&flagAliasScript, "script", "s", false, "SCRIPT")
	CmdRunner.Use(cmdAlias)
}

func alias(command *Command, args *Args) {
	var shell string
	if args.ParamsSize() > 0 {
		shell = args.FirstParam()
	} else {
		shell = os.Getenv("SHELL")
	}

	if shell == "" {
		cmd := "hub alias <shell>"
		if flagAliasScript {
			cmd = "hub alias -s <shell>"
		}
		utils.Check(fmt.Errorf("Error: couldn't detect shell type. Please specify your shell with `%s`", cmd))
	}

	shells := []string{"bash", "zsh", "sh", "ksh", "csh", "tcsh", "fish"}
	shell = filepath.Base(shell)
	var validShell bool
	for _, s := range shells {
		if s == shell {
			validShell = true
			break
		}
	}

	if !validShell {
		err := fmt.Errorf("hub alias: unsupported shell\nsupported shells: %s", strings.Join(shells, " "))
		utils.Check(err)
	}

	if flagAliasScript {
		var alias string
		switch shell {
		case "csh", "tcsh":
			alias = "alias git hub"
		default:
			alias = "alias git=hub"
		}

		ui.Println(alias)
	} else {
		var profile string
		switch shell {
		case "bash":
			profile = "~/.bash_profile"
		case "zsh":
			profile = "~/.zshrc"
		case "ksh":
			profile = "~/.profile"
		case "fish":
			profile = "~/.config/fish/functions/git.fish"
		case "csh":
			profile = "~/.cshrc"
		case "tcsh":
			profile = "~/.tcshrc"
		default:
			profile = "your profile"
		}

		msg := fmt.Sprintf("# Wrap git automatically by adding the following to %s:\n", profile)
		ui.Println(msg)

		var eval string
		switch shell {
		case "fish":
			eval = `function git --description 'Alias for hub, which wraps git to provide extra functionality with GitHub.'
	hub $argv
end`
		case "csh", "tcsh":
			eval = "eval \"`hub alias -s`\""
		default:
			eval = `eval "$(hub alias -s)"`
		}

		indent := regexp.MustCompile(`(?m)^\t+`)
		eval = indent.ReplaceAllStringFunc(eval, func(match string) string {
			return strings.Repeat(" ", len(match) * 4)
		})

		ui.Println(eval)
	}

	os.Exit(0)
}
<commit_msg>go fmt<commit_after>package commands

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/github/hub/ui"
	"github.com/github/hub/utils"
)

var cmdAlias = &Command{
	Run:   alias,
	Usage: "alias [-s] [<SHELL>]",
	Long: `Show shell instructions for wrapping git.

## Options
	-s
		Output shell script suitable for 'eval'.

	<SHELL>
		Specify the type of shell (default: "$SHELL" environment variable).

## See also:

hub(1)
`,
}

var flagAliasScript bool

func init() {
	cmdAlias.Flag.BoolVarP(&flagAliasScript, "script", "s", false, "SCRIPT")
	CmdRunner.Use(cmdAlias)
}

func alias(command *Command, args *Args) {
	var shell string
	if args.ParamsSize() > 0 {
		shell = args.FirstParam()
	} else {
		shell = os.Getenv("SHELL")
	}

	if shell == "" {
		cmd := "hub alias <shell>"
		if flagAliasScript {
			cmd = "hub alias -s <shell>"
		}
		utils.Check(fmt.Errorf("Error: couldn't detect shell type. Please specify your shell with `%s`", cmd))
	}

	shells := []string{"bash", "zsh", "sh", "ksh", "csh", "tcsh", "fish"}
	shell = filepath.Base(shell)
	var validShell bool
	for _, s := range shells {
		if s == shell {
			validShell = true
			break
		}
	}

	if !validShell {
		err := fmt.Errorf("hub alias: unsupported shell\nsupported shells: %s", strings.Join(shells, " "))
		utils.Check(err)
	}

	if flagAliasScript {
		var alias string
		switch shell {
		case "csh", "tcsh":
			alias = "alias git hub"
		default:
			alias = "alias git=hub"
		}

		ui.Println(alias)
	} else {
		var profile string
		switch shell {
		case "bash":
			profile = "~/.bash_profile"
		case "zsh":
			profile = "~/.zshrc"
		case "ksh":
			profile = "~/.profile"
		case "fish":
			profile = "~/.config/fish/functions/git.fish"
		case "csh":
			profile = "~/.cshrc"
		case "tcsh":
			profile = "~/.tcshrc"
		default:
			profile = "your profile"
		}

		msg := fmt.Sprintf("# Wrap git automatically by adding the following to %s:\n", profile)
		ui.Println(msg)

		var eval string
		switch shell {
		case "fish":
			eval = `function git --description 'Alias for hub, which wraps git to provide extra functionality with GitHub.'
	hub $argv
end`
		case "csh", "tcsh":
			eval = "eval \"`hub alias -s`\""
		default:
			eval = `eval "$(hub alias -s)"`
		}

		indent := regexp.MustCompile(`(?m)^\t+`)
		eval = indent.ReplaceAllStringFunc(eval, func(match string) string {
			return strings.Repeat(" ", len(match)*4)
		})

		ui.Println(eval)
	}

	os.Exit(0)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"net/http"
	"time"

	"github.com/jamesnetherton/homehub-cli/service"
)

// NewRebootCommand creates a new command to invoke the Hub Reboot function
func NewRebootCommand(authenticatingCommand *GenericCommand) *AuthenticationRequiringCommand {
	return &AuthenticationRequiringCommand{
		GenericCommand: GenericCommand{
			Name:        "Reboot",
			Description: "Reboots the Home Hub",
			Exec: func(context *CommandContext) {
				context.SetResult(nil, service.GetHub().Reboot())
			},
			PostExec: func(context *CommandContext) {
				fmt.Print("\nWaiting for Home Hub to reboot...")
				attempts := 0
				for {
					attempts++
					response, err := http.Get(service.GetHub().URL)
					if err != nil || response.StatusCode != 200 {
						if attempts == 24 {
							fmt.Println("\nGave up waiting for Home Hub to become available")
							break
						} else {
							fmt.Print(".")
						}
					} else {
						fmt.Println()
						break
					}
					time.Sleep(5000 * time.Millisecond)
				}
			},
		},
		AuthenticatingCommand: authenticatingCommand,
	}
}
<commit_msg>Add sleep after sending reboot command<commit_after>package cmd

import (
	"fmt"
	"net/http"
	"time"

	"github.com/jamesnetherton/homehub-cli/service"
)

// NewRebootCommand creates a new command to invoke the Hub Reboot function
func NewRebootCommand(authenticatingCommand *GenericCommand) *AuthenticationRequiringCommand {
	return &AuthenticationRequiringCommand{
		GenericCommand: GenericCommand{
			Name:        "Reboot",
			Description: "Reboots the Home Hub",
			Exec: func(context *CommandContext) {
				context.SetResult(nil, service.GetHub().Reboot())
			},
			PostExec: func(context *CommandContext) {
				fmt.Print("\nWaiting for Home Hub to reboot...")

				// Give the hub a chance to initialise its reboot sequence
				time.Sleep(10000 * time.Millisecond)

				attempts := 0
				for {
					attempts++
					response, err := http.Get(service.GetHub().URL)
					if err != nil || response.StatusCode != 200 {
						if attempts == 25 {
							fmt.Println("\nGave up waiting for Home Hub to become available")
							break
						} else {
							fmt.Print(".")
						}
					} else {
						fmt.Println()
						break
					}
					time.Sleep(5000 * time.Millisecond)
				}
			},
		},
		AuthenticatingCommand: authenticatingCommand,
	}
}
<|endoftext|>


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

package mapper

import (
	"fmt"
	"github.com/andreaskoch/allmark/converter"
	"github.com/andreaskoch/allmark/parser"
	"github.com/andreaskoch/allmark/path"
	"github.com/andreaskoch/allmark/repository"
	"github.com/andreaskoch/allmark/view"
	"regexp"
	"time"
)

// Pattern which matches all HTML/XML tags
var HtmlTagPattern = regexp.MustCompile(`\<[^\>]*\>`)

func createMessageMapperFunc(pathProvider *path.Provider, targetFormat string) Mapper {
	return func(item *repository.Item) view.Model {

		parsed, err := converter.Convert(item, targetFormat)
		if err != nil {
			return view.Error(fmt.Sprintf("%s", err))
		}

		return view.Model{
			Path:        pathProvider.GetWebRoute(item),
			Title:       getTitle(parsed),
			Description: getDescription(parsed),
			Content:     parsed.ConvertedContent,
			LanguageTag: getTwoLetterLanguageCode(parsed.MetaData.Language),
		}
	}
}

func getDescription(parsedResult *parser.Result) string {
	return parsedResult.MetaData.Date.Format(time.RFC850)
}

func getTitle(parsedResult *parser.Result) string {
	text := HtmlTagPattern.ReplaceAllString(parsedResult.ConvertedContent, "")
	excerpt := getTextExcerpt(text, 30)
	time := parsedResult.MetaData.Date.Format(time.RFC850)

	return fmt.Sprintf("%s ◦ %s", excerpt, time)
}

func getTextExcerpt(text string, length int) string {

	if len(text) <= length {
		return text
	}

	return text[0:length] + " ..."
}
<commit_msg>Changed the title format for messages<commit_after>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mapper

import (
	"fmt"
	"github.com/andreaskoch/allmark/converter"
	"github.com/andreaskoch/allmark/parser"
	"github.com/andreaskoch/allmark/path"
	"github.com/andreaskoch/allmark/repository"
	"github.com/andreaskoch/allmark/view"
	"regexp"
	"time"
)

// Pattern which matches all HTML/XML tags
var HtmlTagPattern = regexp.MustCompile(`\<[^\>]*\>`)

func createMessageMapperFunc(pathProvider *path.Provider, targetFormat string) Mapper {
	return func(item *repository.Item) view.Model {

		parsed, err := converter.Convert(item, targetFormat)
		if err != nil {
			return view.Error(fmt.Sprintf("%s", err))
		}

		return view.Model{
			Path:        pathProvider.GetWebRoute(item),
			Title:       getTitle(parsed),
			Description: getDescription(parsed),
			Content:     parsed.ConvertedContent,
			LanguageTag: getTwoLetterLanguageCode(parsed.MetaData.Language),
		}
	}
}

func getDescription(parsedResult *parser.Result) string {
	return parsedResult.MetaData.Date.Format(time.RFC850)
}

func getTitle(parsedResult *parser.Result) string {
	text := HtmlTagPattern.ReplaceAllString(parsedResult.ConvertedContent, "")
	excerpt := getTextExcerpt(text, 30)
	time := parsedResult.MetaData.Date.Format(time.RFC850)

	return fmt.Sprintf("%s: %s", time, excerpt)
}

func getTextExcerpt(text string, length int) string {

	if len(text) <= length {
		return text
	}

	return text[0:length] + " ..."
}
<|endoftext|>


<commit_before>package caddy

import (
	"net"
	"strconv"
	"testing"
)

/*
// TODO
func TestCaddyStartStop(t *testing.T) {
	caddyfile := "localhost:1984"

	for i := 0; i < 2; i++ {
		_, err := Start(CaddyfileInput{Contents: []byte(caddyfile)})
		if err != nil {
			t.Fatalf("Error starting, iteration %d: %v", i, err)
		}

		client := http.Client{
			Timeout: time.Duration(2 * time.Second),
		}
		resp, err := client.Get("http://localhost:1984")
		if err != nil {
			t.Fatalf("Expected GET request to succeed (iteration %d), but it failed: %v", i, err)
		}
		resp.Body.Close()

		err = Stop()
		if err != nil {
			t.Fatalf("Error stopping, iteration %d: %v", i, err)
		}
	}
}
*/

func TestIsLoopback(t *testing.T) {
	for i, test := range []struct {
		input  string
		expect bool
	}{
		{"example.com", false},
		{"localhost", true},
		{"localhost:1234", true},
		{"localhost:", true},
		{"127.0.0.1", true},
		{"127.0.0.1:443", true},
		{"127.0.1.5", true},
		{"10.0.0.5", false},
		{"12.7.0.1", false},
		{"[::1]", true},
		{"[::1]:1234", true},
		{"::1", true},
		{"::", false},
		{"[::]", false},
		{"local", false},
	} {
		if got, want := IsLoopback(test.input), test.expect; got != want {
			t.Errorf("Test %d (%s): expected %v but was %v", i, test.input, want, got)
		}
	}
}

func TestListenerAddrEqual(t *testing.T) {
	ln1, err := net.Listen("tcp", "[::]:0")
	if err != nil {
		t.Fatal(err)
	}
	defer ln1.Close()

	ln1port := strconv.Itoa(ln1.Addr().(*net.TCPAddr).Port)

	ln2, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer ln2.Close()

	ln2port := strconv.Itoa(ln2.Addr().(*net.TCPAddr).Port)

	for i, test := range []struct {
		ln     net.Listener
		addr   string
		expect bool
	}{
		{ln1, ":1234", false},
		{ln1, "0.0.0.0:1234", false},
		{ln1, ":" + ln1port + "", true},
		{ln1, "0.0.0.0:" + ln1port + "", true},
		{ln2, "127.0.0.1:1234", false},
		{ln2, ":" + ln2port + "", false},
		{ln2, "127.0.0.1:" + ln2port + "", true},
	} {
		if got, want := listenerAddrEqual(test.ln, test.addr), test.expect; got != want {
			t.Errorf("Test %d (%s == %s): expected %v but was %v", i, test.addr, test.ln.Addr().String(), want, got)
		}
	}
}
<commit_msg>Increase code coverage<commit_after>package caddy

import (
	"net"
	"strconv"
	"testing"
)

/*
// TODO
func TestCaddyStartStop(t *testing.T) {
	caddyfile := "localhost:1984"

	for i := 0; i < 2; i++ {
		_, err := Start(CaddyfileInput{Contents: []byte(caddyfile)})
		if err != nil {
			t.Fatalf("Error starting, iteration %d: %v", i, err)
		}

		client := http.Client{
			Timeout: time.Duration(2 * time.Second),
		}
		resp, err := client.Get("http://localhost:1984")
		if err != nil {
			t.Fatalf("Expected GET request to succeed (iteration %d), but it failed: %v", i, err)
		}
		resp.Body.Close()

		err = Stop()
		if err != nil {
			t.Fatalf("Error stopping, iteration %d: %v", i, err)
		}
	}
}
*/

func TestIsLoopback(t *testing.T) {
	for i, test := range []struct {
		input  string
		expect bool
	}{
		{"example.com", false},
		{"localhost", true},
		{"localhost:1234", true},
		{"localhost:", true},
		{"127.0.0.1", true},
		{"127.0.0.1:443", true},
		{"127.0.1.5", true},
		{"10.0.0.5", false},
		{"12.7.0.1", false},
		{"[::1]", true},
		{"[::1]:1234", true},
		{"::1", true},
		{"::", false},
		{"[::]", false},
		{"local", false},
	} {
		if got, want := IsLoopback(test.input), test.expect; got != want {
			t.Errorf("Test %d (%s): expected %v but was %v", i, test.input, want, got)
		}
	}
}

func TestListenerAddrEqual(t *testing.T) {
	ln1, err := net.Listen("tcp", "[::]:0")
	if err != nil {
		t.Fatal(err)
	}
	defer ln1.Close()

	ln1port := strconv.Itoa(ln1.Addr().(*net.TCPAddr).Port)

	ln2, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer ln2.Close()

	ln2port := strconv.Itoa(ln2.Addr().(*net.TCPAddr).Port)

	for i, test := range []struct {
		ln     net.Listener
		addr   string
		expect bool
	}{
		{ln1, ":1234", false},
		{ln1, "0.0.0.0:1234", false},
		{ln1, "0.0.0.0", false},
		{ln1, ":" + ln1port + "", true},
		{ln1, "0.0.0.0:" + ln1port + "", true},
		{ln2, ":" + ln2port + "", false},
		{ln2, "127.0.0.1:1234", false},
		{ln2, "127.0.0.1", false},
		{ln2, "127.0.0.1:" + ln2port + "", true},
	} {
		if got, want := listenerAddrEqual(test.ln, test.addr), test.expect; got != want {
			t.Errorf("Test %d (%s == %s): expected %v but was %v", i, test.addr, test.ln.Addr().String(), want, got)
		}
	}
}
<|endoftext|>