<commit_before>// +build linux

package water

import (
	"os"
	"strings"
	"syscall"
	"unsafe"
)

const (
	cIFF_TUN         = 0x0001
	cIFF_TAP         = 0x0002
	cIFF_NO_PI       = 0x1000
	cIFF_MULTI_QUEUE = 0x0100
)

type ifReq struct {
	Name  [0x10]byte
	Flags uint16
	pad   [0x28 - 0x10 - 2]byte
}

func ioctl(fd uintptr, request int, argp uintptr) error {
	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(request), argp)
	if errno != 0 {
		return os.NewSyscallError("ioctl", errno)
	}
	return nil
}

func newTAP(config Config) (ifce *Interface, err error) {
	file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}

	var flags uint16
	flags = cIFF_TUN | cIFF_NO_PI
	if config.PlatformSpecificParams.MultiQueue {
		flags = cIFF_TUN | cIFF_NO_PI | cIFF_MULTI_QUEUE
	}
	name, err := createInterface(file.Fd(), config.Name, flags)
	if err != nil {
		return nil, err
	}

	if err = setDeviceOptions(file.Fd(), config); err != nil {
		return nil, err
	}

	ifce = &Interface{isTAP: true, ReadWriteCloser: file, name: name}
	return
}

func newTUN(config Config) (ifce *Interface, err error) {
	file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}

	var flags uint16
	flags = cIFF_TUN | cIFF_NO_PI
	if config.PlatformSpecificParams.MultiQueue {
		flags = cIFF_TUN | cIFF_NO_PI | cIFF_MULTI_QUEUE
	}
	name, err := createInterface(file.Fd(), config.Name, flags)
	if err != nil {
		return nil, err
	}

	if err = setDeviceOptions(file.Fd(), config); err != nil {
		return nil, err
	}

	ifce = &Interface{isTAP: false, ReadWriteCloser: file, name: name}
	return
}

func createInterface(fd uintptr, ifName string, flags uint16) (createdIFName string, err error) {
	var req ifReq
	req.Flags = flags
	copy(req.Name[:], ifName)

	err = ioctl(fd, syscall.TUNSETIFF, uintptr(unsafe.Pointer(&req)))
	if err != nil {
		return
	}

	createdIFName = strings.Trim(string(req.Name[:]), "\x00")
	return
}

func setDeviceOptions(fd uintptr, config Config) (err error) {

	// Device Permissions
	if config.Permissions != nil {

		// Set Owner
		if err = ioctl(fd, syscall.TUNSETOWNER, uintptr(config.Permissions.Owner)); err != nil {
			return
		}

		// Set Group
		if err = ioctl(fd, syscall.TUNSETGROUP, uintptr(config.Permissions.Group)); err != nil {
			return
		}
	}

	// Set/Clear Persist Device Flag
	value := 0
	if config.Persist {
		value = 1
	}
	return ioctl(fd, syscall.TUNSETPERSIST, uintptr(value))

}
<commit_msg>Use |=, instead of repeating flags<commit_after>// +build linux

package water

import (
	"os"
	"strings"
	"syscall"
	"unsafe"
)

const (
	cIFF_TUN         = 0x0001
	cIFF_TAP         = 0x0002
	cIFF_NO_PI       = 0x1000
	cIFF_MULTI_QUEUE = 0x0100
)

type ifReq struct {
	Name  [0x10]byte
	Flags uint16
	pad   [0x28 - 0x10 - 2]byte
}

func ioctl(fd uintptr, request int, argp uintptr) error {
	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(request), argp)
	if errno != 0 {
		return os.NewSyscallError("ioctl", errno)
	}
	return nil
}

func newTAP(config Config) (ifce *Interface, err error) {
	file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}

	var flags uint16
	flags = cIFF_TUN | cIFF_NO_PI
	if config.PlatformSpecificParams.MultiQueue {
		flags |= cIFF_MULTI_QUEUE
	}
	name, err := createInterface(file.Fd(), config.Name, flags)
	if err != nil {
		return nil, err
	}

	if err = setDeviceOptions(file.Fd(), config); err != nil {
		return nil, err
	}

	ifce = &Interface{isTAP: true, ReadWriteCloser: file, name: name}
	return
}

func newTUN(config Config) (ifce *Interface, err error) {
	file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}

	var flags uint16
	flags = cIFF_TUN | cIFF_NO_PI
	if config.PlatformSpecificParams.MultiQueue {
		flags |= cIFF_MULTI_QUEUE
	}
	name, err := createInterface(file.Fd(), config.Name, flags)
	if err != nil {
		return nil, err
	}

	if err = setDeviceOptions(file.Fd(), config); err != nil {
		return nil, err
	}

	ifce = &Interface{isTAP: false, ReadWriteCloser: file, name: name}
	return
}

func createInterface(fd uintptr, ifName string, flags uint16) (createdIFName string, err error) {
	var req ifReq
	req.Flags = flags
	copy(req.Name[:], ifName)

	err = ioctl(fd, syscall.TUNSETIFF, uintptr(unsafe.Pointer(&req)))
	if err != nil {
		return
	}

	createdIFName = strings.Trim(string(req.Name[:]), "\x00")
	return
}

func setDeviceOptions(fd uintptr, config Config) (err error) {

	// Device Permissions
	if config.Permissions != nil {

		// Set Owner
		if err = ioctl(fd, syscall.TUNSETOWNER, uintptr(config.Permissions.Owner)); err != nil {
			return
		}

		// Set Group
		if err = ioctl(fd, syscall.TUNSETGROUP, uintptr(config.Permissions.Group)); err != nil {
			return
		}
	}

	// Set/Clear Persist Device Flag
	value := 0
	if config.Persist {
		value = 1
	}
	return ioctl(fd, syscall.TUNSETPERSIST, uintptr(value))

}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go.net/websocket"
	"encoding/json"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/sessions"
	"github.com/joinmytalk/xlog"
	"time"
)

func WebsocketHandler(s *websocket.Conn, dbStore *Store, sessionStore sessions.Store, redisAddr string) {
	xlog.Infof("WebsocketHandler: opened connection")
	r := s.Request()
	session, _ := sessionStore.Get(r, SESSIONNAME)

	sessionData := struct {
		SessionID string `json:"session_id"`
	}{}

	if err := websocket.JSON.Receive(s, &sessionData); err != nil {
		xlog.Errorf("WebsocketHandler: JSON.Receive failed: %v", err)
		return
	}

	owner, sessionID, err := dbStore.GetOwnerForSession(sessionData.SessionID)
	if err != nil {
		xlog.Errorf("GetOwnerForSession failed: %v", err)
		return
	}

	if session.Values["userID"] == nil {
		xlog.Errorf("WebsocketHandler is not authenticated -> slave handler")
		slaveHandler(s, sessionID, dbStore, redisAddr)
	} else if owner == session.Values["userID"].(string) {
		xlog.Infof("WebSocketHandler owner matches -> master handler")
		masterHandler(s, sessionID, dbStore, redisAddr)
	} else {
		xlog.Infof("WebSocketHandler owner doesn't match -> slave handler")
		slaveHandler(s, sessionID, dbStore, redisAddr)
	}
}

type Command struct {
	ID           int       `meddler:"id,pk" json:"-"`
	Timestamp    time.Time `meddler:"timestamp,utctimez" json:"timestamp"`
	Cmd          string    `meddler:"cmd" json:"cmd"`
	Page         int       `meddler:"page" json:"page"`
	SessionID    int       `meddler:"session_id" json:"-"`
	Coordinates  []int     `meddler:"coordinates,json" json:"coords"`
	Color        string    `meddler:"color" json:"color"`
	Width        int       `meddler:"width" json:"width"`
	CanvasWidth  int       `meddler:"canvas_width" json:"canvasWidth"`
	CanvasHeight int       `meddler:"canvas_height" json:"canvasHeight"`
}

func slaveHandler(s *websocket.Conn, sessionID int, dbStore *Store, redisAddr string) {
	xlog.Debugf("entering SlaveHandler")
	c, err := redis.Dial("tcp", redisAddr)
	if err != nil {
		xlog.Errorf("redis.Dial failed: %v", err)
		return
	}
	defer c.Close()

	psc := redis.PubSubConn{Conn: c}
	topic := fmt.Sprintf("session.%d", sessionID)
	psc.Subscribe(topic)
	defer psc.Unsubscribe(topic)

	for {
		switch v := psc.Receive().(type) {
		case redis.Message:
			var cmd Command
			if err := json.Unmarshal(v.Data, &cmd); err != nil {
				break
			}
			if err := websocket.JSON.Send(s, cmd); err != nil {
				xlog.Errorf("slaveHandler: JSON.Send failed: %v", err)
				return
			}
			if cmd.Cmd == "close" {
				return
			}
		case redis.Subscription:
			xlog.Debugf("mkay... redis.Subscription received: %#v", v)
		}
	}
}

func masterHandler(s *websocket.Conn, sessionID int, dbStore *Store, redisAddr string) {
	xlog.Debugf("entering MasterHandler")
	c, err := redis.Dial("tcp", redisAddr)
	if err != nil {
		xlog.Errorf("redis.Dial failed: %v", err)
		return
	}
	defer c.Close()

	for {
		var cmd Command
		if err := websocket.JSON.Receive(s, &cmd); err != nil {
			xlog.Errorf("masterHandler: JSON.Receive failed: %v", err)
			break
		}

		xlog.Debugf("masterHandler: received command: %#v", cmd)

		cmd.SessionID = sessionID
		cmd.Timestamp = time.Now()

		if cmd.Cmd != "clearSlide" {
			if err := dbStore.InsertCommand(&cmd); err != nil {
				xlog.Errorf("Inserting command failed: %v", err)
				break
			}
		}

		executeCommand(cmd, dbStore)

		cmdJSON, _ := json.Marshal(cmd)

		c.Send("PUBLISH", fmt.Sprintf("session.%d", sessionID), string(cmdJSON))
		c.Flush()
	}
	xlog.Debugf("masterHandler: closing connection")
}

func executeCommand(cmd Command, dbStore *Store) {
	switch cmd.Cmd {
	case "clearSlide":
		if err := dbStore.ClearSlide(cmd.SessionID, cmd.Page); err != nil {
			xlog.Errorf("clearSlide for %d page %d failed: %v", cmd.SessionID, cmd.Page, err)
		}
	}
}
<commit_msg>apparently coordinates can be floats.<commit_after>package main

import (
	"code.google.com/p/go.net/websocket"
	"encoding/json"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/sessions"
	"github.com/joinmytalk/xlog"
	"time"
)

func WebsocketHandler(s *websocket.Conn, dbStore *Store, sessionStore sessions.Store, redisAddr string) {
	xlog.Infof("WebsocketHandler: opened connection")
	r := s.Request()
	session, _ := sessionStore.Get(r, SESSIONNAME)

	sessionData := struct {
		SessionID string `json:"session_id"`
	}{}

	if err := websocket.JSON.Receive(s, &sessionData); err != nil {
		xlog.Errorf("WebsocketHandler: JSON.Receive failed: %v", err)
		return
	}

	owner, sessionID, err := dbStore.GetOwnerForSession(sessionData.SessionID)
	if err != nil {
		xlog.Errorf("GetOwnerForSession failed: %v", err)
		return
	}

	if session.Values["userID"] == nil {
		xlog.Errorf("WebsocketHandler is not authenticated -> slave handler")
		slaveHandler(s, sessionID, dbStore, redisAddr)
	} else if owner == session.Values["userID"].(string) {
		xlog.Infof("WebSocketHandler owner matches -> master handler")
		masterHandler(s, sessionID, dbStore, redisAddr)
	} else {
		xlog.Infof("WebSocketHandler owner doesn't match -> slave handler")
		slaveHandler(s, sessionID, dbStore, redisAddr)
	}
}

type Command struct {
	ID           int       `meddler:"id,pk" json:"-"`
	Timestamp    time.Time `meddler:"timestamp,utctimez" json:"timestamp"`
	Cmd          string    `meddler:"cmd" json:"cmd"`
	Page         int       `meddler:"page" json:"page"`
	SessionID    int       `meddler:"session_id" json:"-"`
	Coordinates  []float64 `meddler:"coordinates,json" json:"coords"`
	Color        string    `meddler:"color" json:"color"`
	Width        int       `meddler:"width" json:"width"`
	CanvasWidth  int       `meddler:"canvas_width" json:"canvasWidth"`
	CanvasHeight int       `meddler:"canvas_height" json:"canvasHeight"`
}

func slaveHandler(s *websocket.Conn, sessionID int, dbStore *Store, redisAddr string) {
	xlog.Debugf("entering SlaveHandler")
	c, err := redis.Dial("tcp", redisAddr)
	if err != nil {
		xlog.Errorf("redis.Dial failed: %v", err)
		return
	}
	defer c.Close()

	psc := redis.PubSubConn{Conn: c}
	topic := fmt.Sprintf("session.%d", sessionID)
	psc.Subscribe(topic)
	defer psc.Unsubscribe(topic)

	for {
		switch v := psc.Receive().(type) {
		case redis.Message:
			var cmd Command
			if err := json.Unmarshal(v.Data, &cmd); err != nil {
				break
			}
			if err := websocket.JSON.Send(s, cmd); err != nil {
				xlog.Errorf("slaveHandler: JSON.Send failed: %v", err)
				return
			}
			if cmd.Cmd == "close" {
				return
			}
		case redis.Subscription:
			xlog.Debugf("mkay... redis.Subscription received: %#v", v)
		}
	}
}

func masterHandler(s *websocket.Conn, sessionID int, dbStore *Store, redisAddr string) {
	xlog.Debugf("entering MasterHandler")
	c, err := redis.Dial("tcp", redisAddr)
	if err != nil {
		xlog.Errorf("redis.Dial failed: %v", err)
		return
	}
	defer c.Close()

	for {
		var cmd Command
		if err := websocket.JSON.Receive(s, &cmd); err != nil {
			xlog.Errorf("masterHandler: JSON.Receive failed: %v", err)
			break
		}

		xlog.Debugf("masterHandler: received command: %#v", cmd)

		cmd.SessionID = sessionID
		cmd.Timestamp = time.Now()

		if cmd.Cmd != "clearSlide" {
			if err := dbStore.InsertCommand(&cmd); err != nil {
				xlog.Errorf("Inserting command failed: %v", err)
				break
			}
		}

		executeCommand(cmd, dbStore)

		cmdJSON, _ := json.Marshal(cmd)

		c.Send("PUBLISH", fmt.Sprintf("session.%d", sessionID), string(cmdJSON))
		c.Flush()
	}
	xlog.Debugf("masterHandler: closing connection")
}

func executeCommand(cmd Command, dbStore *Store) {
	switch cmd.Cmd {
	case "clearSlide":
		if err := dbStore.ClearSlide(cmd.SessionID, cmd.Page); err != nil {
			xlog.Errorf("clearSlide for %d page %d failed: %v", cmd.SessionID, cmd.Page, err)
		}
	}
}
<|endoftext|>


<commit_before>package dnsp

import (
	"log"
	"regexp"
	"strings"

	"github.com/miekg/dns"
)

type hosts map[string]struct{}

// isAllowed returns whether we are allowed to resolve this host.
//
// If the server is whitelisting, the result will be true if the host is on the whitelist.
// If the server is blacklisting, the result will be true if the host is NOT on the blacklist.
//
// NOTE: "host" must end with a dot.
func (s *Server) isAllowed(host string) bool {
	s.m.RLock()
	defer s.m.RUnlock()

	_, ok := s.hosts[host]

	if s.white { // whitelist mode
		if ok {
			return true
		}
		for _, rx := range s.hostsRX {
			if rx.MatchString(host) {
				return true
			}
		}
		return false
	}

	// blacklist mode
	if ok {
		return false
	}
	for _, rx := range s.hostsRX {
		if rx.MatchString(host) {
			return false
		}
	}
	return true
}

func (s *Server) filter(qs []dns.Question) []dns.Question {
	result := []dns.Question{}
	for _, q := range qs {
		if s.isAllowed(q.Name) {
			result = append(result, q)
		}
	}
	return result
}

func (s *Server) loadHostEntries(path string) error {
	return readHosts(path, s.addHostEntry)
}

func (s *Server) addHostEntry(host string) {
	if host == "" {
		return
	}
	if host[len(host)-1] != '.' {
		host += "."
	}

	// Plain host string:
	if !strings.ContainsRune(host, '*') {
		s.m.Lock()
		s.hosts[host] = struct{}{}
		s.m.Unlock()
	}

	// Host pattern (regex):
	if pat := compilePattern(host); pat != nil {
		s.m.Lock()
		s.hostsRX = append(s.hostsRX, compilePattern(host))
		s.m.Unlock()
	}
}

func compilePattern(pat string) *regexp.Regexp {
	pat = strings.Replace(pat, ".", `\.`, -1)
	pat = strings.Replace(pat, "*", ".*", -1)
	pat = "^" + pat + `$`
	rx, err := regexp.Compile(pat)
	if err != nil {
		log.Printf("dnsp: could not compile %q: %s", pat, err)
		return nil
	}
	return rx
}
<commit_msg>swap the existing host list instead of updating it in place<commit_after>package dnsp

import (
	"log"
	"regexp"
	"strings"

	"github.com/miekg/dns"
)

type hosts map[string]struct{}

// isAllowed returns whether we are allowed to resolve this host.
//
// If the server is whitelisting, the result will be true if the host is on the whitelist.
// If the server is blacklisting, the result will be true if the host is NOT on the blacklist.
//
// NOTE: "host" must end with a dot.
func (s *Server) isAllowed(host string) bool {
	s.m.RLock()
	defer s.m.RUnlock()

	_, ok := s.hosts[host]

	if s.white { // whitelist mode
		if ok {
			return true
		}
		for _, rx := range s.hostsRX {
			if rx.MatchString(host) {
				return true
			}
		}
		return false
	}

	// blacklist mode
	if ok {
		return false
	}
	for _, rx := range s.hostsRX {
		if rx.MatchString(host) {
			return false
		}
	}
	return true
}

func (s *Server) filter(qs []dns.Question) []dns.Question {
	result := []dns.Question{}
	for _, q := range qs {
		if s.isAllowed(q.Name) {
			result = append(result, q)
		}
	}
	return result
}

// Load the host entries into separate structures and swap the existing entries.
func (s *Server) loadHostEntries(path string) error {
	hosts := hosts{}
	hostsRX := []*regexp.Regexp{}

	if err := readHosts(path, func(host string) {
		if host[len(host)-1] != '.' {
			host += "."
		}

		if !strings.ContainsRune(host, '*') {
			// Plain host string:
			hosts[host] = struct{}{}
		} else if pat := compilePattern(host); pat != nil {
			// Host pattern (regex):
			hostsRX = append(hostsRX, compilePattern(host))
		}
	}); err != nil {
		return err
	}

	s.m.Lock()
	s.hosts = hosts
	s.hostsRX = hostsRX
	s.m.Unlock()

	return nil
}

func (s *Server) addHostEntry(host string) {
	if host == "" {
		return
	}
	if host[len(host)-1] != '.' {
		host += "."
	}

	if !strings.ContainsRune(host, '*') {
		// Plain host string:
		s.m.Lock()
		s.hosts[host] = struct{}{}
		s.m.Unlock()
	} else if pat := compilePattern(host); pat != nil {
		// Host pattern (regex):
		s.m.Lock()
		s.hostsRX = append(s.hostsRX, compilePattern(host))
		s.m.Unlock()
	}
}

func compilePattern(pat string) *regexp.Regexp {
	pat = strings.Replace(pat, ".", `\.`, -1)
	pat = strings.Replace(pat, "*", ".*", -1)
	pat = "^" + pat + `$`
	rx, err := regexp.Compile(pat)
	if err != nil {
		log.Printf("dnsp: could not compile %q: %s", pat, err)
		return nil
	}
	return rx
}
<|endoftext|>


<commit_before>package GenVersionFile

func Version () string {
  return "0.0.0"
}
<commit_msg>version update<commit_after>package GenVersionFile

func Version () string {
  return "0.0.1"
}
<|endoftext|>


<commit_before>package GenVersionFile

func Version () string {
  return "0.0.1"
}
<commit_msg>version update<commit_after>package GenVersionFile

func Version () string {
  return "0.0.2"
}
<|endoftext|>


<commit_before>// +build linux
// +build cgo

package idmap

import (
	"fmt"
	"unsafe"

	"github.com/lxc/lxd/shared"
)

// #cgo LDFLAGS: -lacl
/*
#define _GNU_SOURCE
#include <byteswap.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/capability.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/acl.h>

// Needs to be included at the end
#include <attr/xattr.h>

#ifndef VFS_CAP_REVISION_1
#define VFS_CAP_REVISION_1 0x01000000
#endif

#ifndef VFS_CAP_REVISION_2
#define VFS_CAP_REVISION_2 0x02000000
#endif

#ifndef VFS_CAP_REVISION_3
#define VFS_CAP_REVISION_3 0x03000000
struct vfs_ns_cap_data {
	__le32 magic_etc;
	struct {
		__le32 permitted;
		__le32 inheritable;
	} data[VFS_CAP_U32];
	__le32 rootid;
};
#endif

#if __BYTE_ORDER == __BIG_ENDIAN
#define BE32_TO_LE32(x) bswap_32(x)
#else
#define BE32_TO_LE32(x) (x)
#endif

int set_vfs_ns_caps(char *path, char *caps, ssize_t len, uint32_t uid)
{
	// Works because vfs_ns_cap_data is a superset of vfs_cap_data (rootid
	// field added to the end)
	struct vfs_ns_cap_data ns_xattr;

	memset(&ns_xattr, 0, sizeof(ns_xattr));
	memcpy(&ns_xattr, caps, len);
	ns_xattr.magic_etc &= ~(VFS_CAP_REVISION_1 | VFS_CAP_REVISION_2);
	ns_xattr.magic_etc |= VFS_CAP_REVISION_3;
	ns_xattr.rootid = BE32_TO_LE32(uid);

	return setxattr(path, "security.capability", &ns_xattr, sizeof(ns_xattr), 0);
}

int shiftowner(char *basepath, char *path, int uid, int gid)
{
	int fd, ret;
	char fdpath[PATH_MAX], realpath[PATH_MAX];
	struct stat sb;

	fd = open(path, O_PATH | O_NOFOLLOW);
	if (fd < 0) {
		perror("Failed open");
		return 1;
	}

	ret = sprintf(fdpath, "/proc/self/fd/%d", fd);
	if (ret < 0) {
		perror("Failed sprintf");
		close(fd);
		return 1;
	}

	ret = readlink(fdpath, realpath, PATH_MAX);
	if (ret < 0) {
		perror("Failed readlink");
		close(fd);
		return 1;
	}

	if (strlen(realpath) < strlen(basepath)) {
		printf("Invalid path, source (%s) is outside of basepath (%s)\n", realpath, basepath);
		close(fd);
		return 1;
	}

	if (strncmp(realpath, basepath, strlen(basepath))) {
		printf("Invalid path, source (%s) is outside of basepath " "(%s).\n", realpath, basepath);
		close(fd);
		return 1;
	}

	ret = fstat(fd, &sb);
	if (ret < 0) {
		perror("Failed fstat");
		close(fd);
		return 1;
	}

	ret = fchownat(fd, "", uid, gid, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
	if (ret < 0) {
		perror("Failed chown");
		close(fd);
		return 1;
	}

	if (!S_ISLNK(sb.st_mode)) {
		ret = chmod(fdpath, sb.st_mode);
		if (ret < 0) {
			perror("Failed chmod");
			close(fd);
			return 1;
		}
	}

	close(fd);
	return 0;
}
*/
import "C"

// ShiftOwner updates uid and gid for a file when entering/exiting a namespace
func ShiftOwner(basepath string, path string, uid int, gid int) error {
	cbasepath := C.CString(basepath)
	defer C.free(unsafe.Pointer(cbasepath))

	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	r := C.shiftowner(cbasepath, cpath, C.int(uid), C.int(gid))
	if r != 0 {
		return fmt.Errorf("Failed to change ownership of: %s", path)
	}

	return nil
}

// GetCaps extracts the list of capabilities effective on the file
func GetCaps(path string) ([]byte, error) {
	xattrs, err := shared.GetAllXattr(path)
	if err != nil {
		return nil, err
	}

	valueStr, ok := xattrs["security.capability"]
	if !ok {
		return nil, nil
	}

	return []byte(valueStr), nil
}

// SetCaps applies the caps for a particular root uid
func SetCaps(path string, caps []byte, uid int64) error {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	ccaps := C.CString(string(caps))
	defer C.free(unsafe.Pointer(ccaps))

	r := C.set_vfs_ns_caps(cpath, ccaps, C.ssize_t(len(caps)), C.uint32_t(uid))
	if r != 0 {
		return fmt.Errorf("Failed to apply capabilities to: %s", path)
	}

	return nil
}

// ShiftACL updates uid and gid for file ACLs when entering/exiting a namespace
func ShiftACL(path string, shiftIds func(uid int64, gid int64) (int64, int64)) error {
	err := shiftAclType(path, C.ACL_TYPE_ACCESS, shiftIds)
	if err != nil {
		return err
	}

	err = shiftAclType(path, C.ACL_TYPE_DEFAULT, shiftIds)
	if err != nil {
		return err
	}

	return nil
}

func shiftAclType(path string, aclType _Ctype_acl_type_t, shiftIds func(uid int64, gid int64) (int64, int64)) error {
	// Convert the path to something usable with cgo
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	// Read the current ACL set for the requested type
	acl := C.acl_get_file(cpath, aclType)
	if acl == nil {
		return nil
	}
	defer C.acl_free(unsafe.Pointer(acl))

	newAcl := C.acl_init(0)
	defer C.acl_free(unsafe.Pointer(newAcl))

	// Iterate through all ACL entries
	update := false
	for entryId := C.ACL_FIRST_ENTRY; ; entryId = C.ACL_NEXT_ENTRY {
		var ent C.acl_entry_t
		var newEnt C.acl_entry_t
		var tag C.acl_tag_t

		// Get the ACL entry
		ret := C.acl_get_entry(acl, C.int(entryId), &ent)
		if ret == 0 {
			break
		} else if ret < 0 {
			return fmt.Errorf("Failed to get the ACL entry for %s", path)
		}

		// Setup the new entry
		ret = C.acl_create_entry(&newAcl, &newEnt)
		if ret == -1 {
			return fmt.Errorf("Failed to allocate a new ACL entry for %s", path)
		}

		ret = C.acl_copy_entry(newEnt, ent)
		if ret == -1 {
			return fmt.Errorf("Failed to copy the ACL entry for %s", path)
		}

		// Get the ACL type
		ret = C.acl_get_tag_type(newEnt, &tag)
		if ret == -1 {
			return fmt.Errorf("Failed to get the ACL type for %s", path)
		}

		// We only care about user and group ACLs, copy anything else
		if tag != C.ACL_USER && tag != C.ACL_GROUP {
			continue
		}

		// Get the value
		idp := (*C.id_t)(C.acl_get_qualifier(newEnt))
		if idp == nil {
			return fmt.Errorf("Failed to get current ACL value for %s", path)
		}

		// Shift the value
		newId, _ := shiftIds((int64)(*idp), -1)

		// Update the new entry with the shifted value
		ret = C.acl_set_qualifier(newEnt, unsafe.Pointer(&newId))
		if ret == -1 {
			return fmt.Errorf("Failed to set ACL qualifier on %s", path)
		}

		update = true
	}

	// Update the on-disk ACLs to match
	if update {
		ret := C.acl_set_file(cpath, aclType, newAcl)
		if ret == -1 {
			return fmt.Errorf("Failed to change ACLs on %s", path)
		}
	}

	return nil
}
<commit_msg>shared/idmap: Fix xattr.h import<commit_after>// +build linux
// +build cgo

package idmap

import (
	"fmt"
	"unsafe"

	"github.com/lxc/lxd/shared"
)

// #cgo LDFLAGS: -lacl
/*
#define _GNU_SOURCE
#include <byteswap.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/capability.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/acl.h>

// Needs to be included at the end
#include <sys/xattr.h>

#ifndef VFS_CAP_REVISION_1
#define VFS_CAP_REVISION_1 0x01000000
#endif

#ifndef VFS_CAP_REVISION_2
#define VFS_CAP_REVISION_2 0x02000000
#endif

#ifndef VFS_CAP_REVISION_3
#define VFS_CAP_REVISION_3 0x03000000
struct vfs_ns_cap_data {
	__le32 magic_etc;
	struct {
		__le32 permitted;
		__le32 inheritable;
	} data[VFS_CAP_U32];
	__le32 rootid;
};
#endif

#if __BYTE_ORDER == __BIG_ENDIAN
#define BE32_TO_LE32(x) bswap_32(x)
#else
#define BE32_TO_LE32(x) (x)
#endif

int set_vfs_ns_caps(char *path, char *caps, ssize_t len, uint32_t uid)
{
	// Works because vfs_ns_cap_data is a superset of vfs_cap_data (rootid
	// field added to the end)
	struct vfs_ns_cap_data ns_xattr;

	memset(&ns_xattr, 0, sizeof(ns_xattr));
	memcpy(&ns_xattr, caps, len);
	ns_xattr.magic_etc &= ~(VFS_CAP_REVISION_1 | VFS_CAP_REVISION_2);
	ns_xattr.magic_etc |= VFS_CAP_REVISION_3;
	ns_xattr.rootid = BE32_TO_LE32(uid);

	return setxattr(path, "security.capability", &ns_xattr, sizeof(ns_xattr), 0);
}

int shiftowner(char *basepath, char *path, int uid, int gid)
{
	int fd, ret;
	char fdpath[PATH_MAX], realpath[PATH_MAX];
	struct stat sb;

	fd = open(path, O_PATH | O_NOFOLLOW);
	if (fd < 0) {
		perror("Failed open");
		return 1;
	}

	ret = sprintf(fdpath, "/proc/self/fd/%d", fd);
	if (ret < 0) {
		perror("Failed sprintf");
		close(fd);
		return 1;
	}

	ret = readlink(fdpath, realpath, PATH_MAX);
	if (ret < 0) {
		perror("Failed readlink");
		close(fd);
		return 1;
	}

	if (strlen(realpath) < strlen(basepath)) {
		printf("Invalid path, source (%s) is outside of basepath (%s)\n", realpath, basepath);
		close(fd);
		return 1;
	}

	if (strncmp(realpath, basepath, strlen(basepath))) {
		printf("Invalid path, source (%s) is outside of basepath " "(%s).\n", realpath, basepath);
		close(fd);
		return 1;
	}

	ret = fstat(fd, &sb);
	if (ret < 0) {
		perror("Failed fstat");
		close(fd);
		return 1;
	}

	ret = fchownat(fd, "", uid, gid, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
	if (ret < 0) {
		perror("Failed chown");
		close(fd);
		return 1;
	}

	if (!S_ISLNK(sb.st_mode)) {
		ret = chmod(fdpath, sb.st_mode);
		if (ret < 0) {
			perror("Failed chmod");
			close(fd);
			return 1;
		}
	}

	close(fd);
	return 0;
}
*/
import "C"

// ShiftOwner updates uid and gid for a file when entering/exiting a namespace
func ShiftOwner(basepath string, path string, uid int, gid int) error {
	cbasepath := C.CString(basepath)
	defer C.free(unsafe.Pointer(cbasepath))

	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	r := C.shiftowner(cbasepath, cpath, C.int(uid), C.int(gid))
	if r != 0 {
		return fmt.Errorf("Failed to change ownership of: %s", path)
	}

	return nil
}

// GetCaps extracts the list of capabilities effective on the file
func GetCaps(path string) ([]byte, error) {
	xattrs, err := shared.GetAllXattr(path)
	if err != nil {
		return nil, err
	}

	valueStr, ok := xattrs["security.capability"]
	if !ok {
		return nil, nil
	}

	return []byte(valueStr), nil
}

// SetCaps applies the caps for a particular root uid
func SetCaps(path string, caps []byte, uid int64) error {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	ccaps := C.CString(string(caps))
	defer C.free(unsafe.Pointer(ccaps))

	r := C.set_vfs_ns_caps(cpath, ccaps, C.ssize_t(len(caps)), C.uint32_t(uid))
	if r != 0 {
		return fmt.Errorf("Failed to apply capabilities to: %s", path)
	}

	return nil
}

// ShiftACL updates uid and gid for file ACLs when entering/exiting a namespace
func ShiftACL(path string, shiftIds func(uid int64, gid int64) (int64, int64)) error {
	err := shiftAclType(path, C.ACL_TYPE_ACCESS, shiftIds)
	if err != nil {
		return err
	}

	err = shiftAclType(path, C.ACL_TYPE_DEFAULT, shiftIds)
	if err != nil {
		return err
	}

	return nil
}

func shiftAclType(path string, aclType _Ctype_acl_type_t, shiftIds func(uid int64, gid int64) (int64, int64)) error {
	// Convert the path to something usable with cgo
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	// Read the current ACL set for the requested type
	acl := C.acl_get_file(cpath, aclType)
	if acl == nil {
		return nil
	}
	defer C.acl_free(unsafe.Pointer(acl))

	newAcl := C.acl_init(0)
	defer C.acl_free(unsafe.Pointer(newAcl))

	// Iterate through all ACL entries
	update := false
	for entryId := C.ACL_FIRST_ENTRY; ; entryId = C.ACL_NEXT_ENTRY {
		var ent C.acl_entry_t
		var newEnt C.acl_entry_t
		var tag C.acl_tag_t

		// Get the ACL entry
		ret := C.acl_get_entry(acl, C.int(entryId), &ent)
		if ret == 0 {
			break
		} else if ret < 0 {
			return fmt.Errorf("Failed to get the ACL entry for %s", path)
		}

		// Setup the new entry
		ret = C.acl_create_entry(&newAcl, &newEnt)
		if ret == -1 {
			return fmt.Errorf("Failed to allocate a new ACL entry for %s", path)
		}

		ret = C.acl_copy_entry(newEnt, ent)
		if ret == -1 {
			return fmt.Errorf("Failed to copy the ACL entry for %s", path)
		}

		// Get the ACL type
		ret = C.acl_get_tag_type(newEnt, &tag)
		if ret == -1 {
			return fmt.Errorf("Failed to get the ACL type for %s", path)
		}

		// We only care about user and group ACLs, copy anything else
		if tag != C.ACL_USER && tag != C.ACL_GROUP {
			continue
		}

		// Get the value
		idp := (*C.id_t)(C.acl_get_qualifier(newEnt))
		if idp == nil {
			return fmt.Errorf("Failed to get current ACL value for %s", path)
		}

		// Shift the value
		newId, _ := shiftIds((int64)(*idp), -1)

		// Update the new entry with the shifted value
		ret = C.acl_set_qualifier(newEnt, unsafe.Pointer(&newId))
		if ret == -1 {
			return fmt.Errorf("Failed to set ACL qualifier on %s", path)
		}

		update = true
	}

	// Update the on-disk ACLs to match
	if update {
		ret := C.acl_set_file(cpath, aclType, newAcl)
		if ret == -1 {
			return fmt.Errorf("Failed to change ACLs on %s", path)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// +build linux darwin

package logging

import (
	log "github.com/lxc/lxd/shared/log15"
)

// getSystemHandler on Linux writes messages to syslog.
func getSystemHandler(syslog string, debug bool, format log.Format) log.Handler {
	// SyslogHandler
	if syslog != "" {
		if !debug {
			return log.LvlFilterHandler(
				log.LvlInfo,
				log.Must.SyslogHandler(syslog, format),
			)
		}

		return log.Must.SyslogHandler(syslog, format)
	}

	return nil
}
<commit_msg>shared/logging: Add freebsd build conditional to log_posix.go<commit_after>// +build linux darwin freebsd

package logging

import (
	log "github.com/lxc/lxd/shared/log15"
)

// getSystemHandler on Linux writes messages to syslog.
func getSystemHandler(syslog string, debug bool, format log.Format) log.Handler {
	// SyslogHandler
	if syslog != "" {
		if !debug {
			return log.LvlFilterHandler(
				log.LvlInfo,
				log.Must.SyslogHandler(syslog, format),
			)
		}

		return log.Must.SyslogHandler(syslog, format)
	}

	return nil
}
<|endoftext|>


<commit_before><commit_msg>Test not specific to Lint - commenting out untiul lint refactored for testability.<commit_after><|endoftext|>


<commit_before>package db

import (
	"encoding/json"
	"log"

	"github.com/bosssauce/ponzu/content"
	"github.com/bosssauce/ponzu/system/admin/config"

	"github.com/boltdb/bolt"
	"github.com/nilslice/jwt"
)

var store *bolt.DB

// Close exports the abillity to close our db file. Should be called with defer
// after call to Init() from the same place.
func Close() {
	err := store.Close()
	if err != nil {
		log.Println(err)
	}
}

// Init creates a db connection, initializes db with required info, sets secrets
func Init() {
	var err error
	store, err = bolt.Open("system.db", 0666, nil)
	if err != nil {
		log.Fatalln(err)
	}

	err = store.Update(func(tx *bolt.Tx) error {
		// initialize db with all content type buckets & sorted bucket for type
		for t := range content.Types {
			_, err := tx.CreateBucketIfNotExists([]byte(t))
			if err != nil {
				return err
			}

			_, err = tx.CreateBucketIfNotExists([]byte(t + "__sorted"))
			if err != nil {
				return err
			}
		}

		// init db with other buckets as needed
		buckets := []string{"__config", "__users", "__contentIndex"}
		for _, name := range buckets {
			_, err := tx.CreateBucketIfNotExists([]byte(name))
			if err != nil {
				return err
			}
		}

		// seed db with configs structure if not present
		b := tx.Bucket([]byte("__config"))
		if b.Get([]byte("settings")) == nil {
			j, err := json.Marshal(&config.Config{})
			if err != nil {
				return err
			}

			err = b.Put([]byte("settings"), j)
			if err != nil {
				return err
			}
		}

		clientSecret := ConfigCache("client_secret")

		if clientSecret != "" {
			jwt.Secret([]byte(clientSecret))
		}

		return nil
	})
	if err != nil {
		log.Fatalln("Coudn't initialize db with buckets.", err)
	}

	go func() {
		for t := range content.Types {
			SortContent(t)
		}
	}()

}

// SystemInitComplete checks if there is at least 1 admin user in the db which
// would indicate that the system has been configured to the minimum required.
func SystemInitComplete() bool {
	complete := false

	err := store.View(func(tx *bolt.Tx) error {
		users := tx.Bucket([]byte("__users"))

		err := users.ForEach(func(k, v []byte) error {
			complete = true
			return nil
		})
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		complete = false
		log.Fatalln(err)
	}

	return complete
}
<commit_msg>adding cache invalidation to system start/init<commit_after>package db

import (
	"encoding/json"
	"log"

	"github.com/bosssauce/ponzu/content"
	"github.com/bosssauce/ponzu/system/admin/config"

	"github.com/boltdb/bolt"
	"github.com/nilslice/jwt"
)

var store *bolt.DB

// Close exports the abillity to close our db file. Should be called with defer
// after call to Init() from the same place.
func Close() {
	err := store.Close()
	if err != nil {
		log.Println(err)
	}
}

// Init creates a db connection, initializes db with required info, sets secrets
func Init() {
	var err error
	store, err = bolt.Open("system.db", 0666, nil)
	if err != nil {
		log.Fatalln(err)
	}

	err = store.Update(func(tx *bolt.Tx) error {
		// initialize db with all content type buckets & sorted bucket for type
		for t := range content.Types {
			_, err := tx.CreateBucketIfNotExists([]byte(t))
			if err != nil {
				return err
			}

			_, err = tx.CreateBucketIfNotExists([]byte(t + "__sorted"))
			if err != nil {
				return err
			}
		}

		// init db with other buckets as needed
		buckets := []string{"__config", "__users", "__contentIndex"}
		for _, name := range buckets {
			_, err := tx.CreateBucketIfNotExists([]byte(name))
			if err != nil {
				return err
			}
		}

		// seed db with configs structure if not present
		b := tx.Bucket([]byte("__config"))
		if b.Get([]byte("settings")) == nil {
			j, err := json.Marshal(&config.Config{})
			if err != nil {
				return err
			}

			err = b.Put([]byte("settings"), j)
			if err != nil {
				return err
			}
		}

		clientSecret := ConfigCache("client_secret")

		if clientSecret != "" {
			jwt.Secret([]byte(clientSecret))
		}

		return nil
	})
	if err != nil {
		log.Fatalln("Coudn't initialize db with buckets.", err)
	}

	// invalidate cache on system start
	err = InvalidateCache()
	if err != nil {
		log.Fatalln("Failed to invalidate cache.", err)
	}

	go func() {
		for t := range content.Types {
			SortContent(t)
		}
	}()

}

// SystemInitComplete checks if there is at least 1 admin user in the db which
// would indicate that the system has been configured to the minimum required.
func SystemInitComplete() bool {
	complete := false

	err := store.View(func(tx *bolt.Tx) error {
		users := tx.Bucket([]byte("__users"))

		err := users.ForEach(func(k, v []byte) error {
			complete = true
			return nil
		})
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		complete = false
		log.Fatalln(err)
	}

	return complete
}
<|endoftext|>


<commit_before>// refernces:
//   https://code.msdn.microsoft.com/windowsapps/In-app-purchase-receipt-c3e0bce4
//   https://github.com/amdonov/xmlsig
//   http://seepiagames.blogspot.com/2013/10/cloud-service-windows-phone-application.html
//   https://code.google.com/p/go/issues/detail?id=8265

package main

import (
	"bufio"
	"bytes"
	"crypto"
	"crypto/rsa"
	"crypto/sha256"
	"encoding/base64"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"sort"
)

const DIGEST_VALUE_TAG = "DigestValue"
const SIGNATURE_VALUE_TAG = "SignatureValue"
const SIGNATURE_TAG = "Signature"
const SIGNEDINFO_TAG = "SignedInfo"
const SIGNEDINFO_XMLNS = "http://www.w3.org/2000/09/xmldsig#"

// Taken largely from an example in "Programming In Go"
// Keeping it separate from my stuff
type stack []interface{}

func (s *stack) Len() int {
	return len(*s)
}

func (s *stack) Push(x interface{}) {
	*s = append(*s, x)
}

func (s *stack) Top() (interface{}, error) {
	if len(*s) == 0 {
		return nil, errors.New("Empty stack")
	}
	return (*s)[s.Len()-1], nil
}

func (s *stack) Pop() (interface{}, error) {
	theStack := *s
	if len(theStack) == 0 {
		return nil, errors.New("Empty stack")
	}
	x := theStack[len(theStack)-1]
	*s = theStack[:len(theStack)-1]
	return x, nil
}

type canonAtt []xml.Attr

func (att canonAtt) Len() int {
	return len(att)
}

func (att canonAtt) Swap(i, j int) {
	att[i], att[j] = att[j], att[i]
}

func (att canonAtt) Less(i, j int) bool {
	iName := att[i].Name.Local
	jName := att[j].Name.Local
	if iName == "xmlns" {
		return true
	}
	if jName == "xmlns" {
		return false
	}
	return att[i].Name.Local < att[j].Name.Local
}

func digestBase64(data string) string {
    return base64.StdEncoding.EncodeToString(digest(data))
}

func digest(data string) []byte {
	h := sha256.New()
	h.Write([]byte(data))
	return h.Sum(nil)
}

func ParseAndCanonicalizeXml(xmlstring string) (string, string, string, string, error) {

	// write xml string to a buffer
	var buffer, out bytes.Buffer
	writer := bufio.NewWriter(&buffer)
    writer.Write([]byte(xmlstring))
    writer.Flush()

	// read from the buffer
	decoder := xml.NewDecoder(bytes.NewReader(buffer.Bytes()))
	outWriter := bufio.NewWriter(&out)

    charData := ""
    tagStart := false
	stack := &stack{}

    digestValue := ""
    signatureValue := ""
    signatureTagStart := -1
    signatureTagEnd := -1
    signedinfoTagStart := -1
    signedinfoTagEnd := -1

	writeStartElement := func(writer io.Writer, start xml.StartElement) {
		fmt.Fprintf(writer, "<%s", start.Name.Local)
		sort.Sort(canonAtt(start.Attr))
		currentNs, err := stack.Top()
		if err != nil {
			// No namespaces yet declare ours
			fmt.Fprintf(writer, " %s=\"%s\"", "xmlns", start.Name.Space)
		} else {
			// Different namespace declare ours
			if currentNs != start.Name.Space {
				fmt.Fprintf(writer, " %s=\"%s\"", "xmlns", start.Name.Space)
			}
            // inhiret tag Signature's namespace for SignedInfo
            // just for conveniance...
            if start.Name.Local == SIGNEDINFO_TAG {
                fmt.Fprintf(writer, " %s=\"%s\"", "xmlns", SIGNEDINFO_XMLNS)
            }
		}

		stack.Push(start.Name.Space)
		for i := range start.Attr {
			if "xmlns" != start.Attr[i].Name.Local {
				fmt.Fprintf(writer, " %s=\"%s\"", start.Attr[i].Name.Local, start.Attr[i].Value)
			}
		}
		fmt.Fprint(writer, ">")
	}

    // parse xml token
	for {
		token, err := decoder.Token()
		if err != nil {
			break
		}

		switch t := token.(type) {
		case xml.StartElement:
            if t.Name.Local == SIGNATURE_TAG {
                // .<Signature
                outWriter.Flush()
                signatureTagStart = out.Len()
            } else if t.Name.Local == SIGNEDINFO_TAG {
                // .<SignedInfo
                outWriter.Flush()
                signedinfoTagStart = out.Len()
            }
			writeStartElement(outWriter, t)
            charData = ""
            tagStart = true

		case xml.EndElement:
            if charData != "" {
                outWriter.Write([]byte(charData))
                if t.Name.Local == DIGEST_VALUE_TAG {
                    digestValue = charData
                }
                if t.Name.Local == SIGNATURE_VALUE_TAG {
                    signatureValue = charData
                }
            }
            charData = ""
            tagStart = false

			stack.Pop()
			fmt.Fprintf(outWriter, "</%s>", t.Name.Local)

            if t.Name.Local == SIGNATURE_TAG {
                // </Signature>.
                outWriter.Flush()
                signatureTagEnd = out.Len()
            } else if t.Name.Local == SIGNEDINFO_TAG {
                // </SignedInfo>.
                outWriter.Flush()
                signedinfoTagEnd = out.Len()
            }

		case xml.CharData:
            if tagStart {
                charData = string(t)
            }
		}
	}

    // the whole xml
	outWriter.Flush()
    canonicalizeXmlBytes := out.Bytes()

    // ...<Signatrue><SignInfo>...</SignInfo></Signature>
    if signatureTagStart == -1 || signatureTagEnd == -1 || signedinfoTagStart == -1 || signedinfoTagEnd == -1 {
        return "", "", "", "", errors.New(fmt.Sprintf("can't find tag %s or %s", SIGNATURE_TAG, SIGNEDINFO_TAG))
    }
    if digestValue == "" {
        return "", "", "", "", errors.New("can't find digest value")
    }
    if signatureValue == "" {
        return "", "", "", "", errors.New("can't find signature value")
    }

    // extract SignInfo node
    signinfoNodeStr := string(canonicalizeXmlBytes[signedinfoTagStart:signedinfoTagEnd])
    // remove Signature node
    dataNodeStr := string(canonicalizeXmlBytes[:signatureTagStart]) + string(canonicalizeXmlBytes[signatureTagEnd:])

    return dataNodeStr, signinfoNodeStr, digestValue, signatureValue, nil
}

func main() {
    dataStr, signInfoStr, digestStr, signatureStr, err := ParseAndCanonicalizeXml(xmlstring)
    if err != nil {
        fmt.Printf("ParseAndCanonicalizeXml %s failed: %s\n", xmlstring, err.Error())
        return
    }
    fmt.Printf("--data: \n%s\n--signInfo:\n%s\n--digest:\n%s\n--signature:\n%s\n",
        dataStr, signInfoStr, digestStr, signatureStr)
    fmt.Printf("\n--calculated base64 digest: \n%s\n", digestBase64(dataStr))

    bytes, err := ioutil.ReadFile(certFile)
    if err != nil {
        fmt.Printf("read cert file failed: %s\n", err.Error())
        return
    }

    cert, err := MyParseCertificate(bytes)
    if err != nil {
        fmt.Printf("parse certificate failed: %s, cert: %v\n", err.Error(), cert)
        return
    }

    publickey := cert.PublicKey
    pub, ok := publickey.(*rsa.PublicKey)
    if !ok {
        fmt.Printf("invalid rsa publickey: %#v\n", publickey)
        return
    }

    signatureBytes, err := base64.StdEncoding.DecodeString(signatureStr)
    if err != nil {
        fmt.Printf("base64 decode signature failed: %s\n", err.Error())
        return
    }

    err = rsa.VerifyPKCS1v15(pub, crypto.SHA256, digest(signInfoStr), signatureBytes)
    if err != nil {
        fmt.Printf("rsa.VerifyPKCS1v15 failed: %s\n", err.Error())
        return
    }
    fmt.Printf("\nrsa verification passed!\n")
}

const certFile = "IapReceiptProduction.cer"

const xmlstring string =`
<?xml version="1.0"?>
<Receipt Version="1.0" CertificateId="A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD" xmlns="http://schemas.microsoft.com/windows/2012/store/receipt">
  <ProductReceipt PurchasePrice="$20.89" PurchaseDate="2012-11-30T21:32:07.096Z" Id="2f9c5c8f-3e1d-4fc7-a871-ac58f7e78053" AppId="3ec6cd9a-ca82-4d38-bfdf-ecafdb35a738" ProductId="Test" ProductType="Consumable" PublisherDeviceId="Test" MicrosoftProductId="59ef70aa-7099-4679-889e-f21919bfd2c6" />
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
      <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
      <Reference URI="">
        <Transforms>
          <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
        <DigestValue>FyFb1HGm+yeOIjt18M6TPD4Qzeu469vwDbQs7w72mdA=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>noct5CYBtRwBxVxkUeZIzeDyruLGVBqBMuFuBytpouPLACnQ5dbzdRvWX4XN67IUo0J2FW8DoYcMbf3sAS+PeKKV8SLnU+l8K1hWEbbbugHZezStTzwwkYcZuCTnAk7BYO0aiZWuXm9GiZGT9iyXsYtU1/u87L+llnVibU/m7gV8tD3vG0tVkjzV20C8666mHUsY/jxeq3ed7YY9CT0SDrh5PeL4ESaopBLcncHo/e6lcjyoKbO3e6YuIpsi8DVueeKNhpTlwa5yc0O3qzc5SGnT4Kbhj9NBEXf15/oTaLlg7lJhnQZ0mY+yR8vc4D0SkqD6e5Uc4u64hnu+g3Hphg==</SignatureValue>
  </Signature>
</Receipt>
`
<commit_msg>code format<commit_after>// refernces:
//   https://code.msdn.microsoft.com/windowsapps/In-app-purchase-receipt-c3e0bce4
//   https://github.com/amdonov/xmlsig
//   http://seepiagames.blogspot.com/2013/10/cloud-service-windows-phone-application.html
//   https://code.google.com/p/go/issues/detail?id=8265

package main

import (
	"bufio"
	"bytes"
	"crypto"
	"crypto/rsa"
	"crypto/sha256"
	"encoding/base64"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"sort"
)

const DIGEST_VALUE_TAG = "DigestValue"
const SIGNATURE_VALUE_TAG = "SignatureValue"
const SIGNATURE_TAG = "Signature"
const SIGNEDINFO_TAG = "SignedInfo"
const SIGNEDINFO_XMLNS = "http://www.w3.org/2000/09/xmldsig#"

// Taken largely from an example in "Programming In Go"
// Keeping it separate from my stuff
type stack []interface{}

func (s *stack) Len() int {
	return len(*s)
}

func (s *stack) Push(x interface{}) {
	*s = append(*s, x)
}

func (s *stack) Top() (interface{}, error) {
	if len(*s) == 0 {
		return nil, errors.New("Empty stack")
	}
	return (*s)[s.Len()-1], nil
}

func (s *stack) Pop() (interface{}, error) {
	theStack := *s
	if len(theStack) == 0 {
		return nil, errors.New("Empty stack")
	}
	x := theStack[len(theStack)-1]
	*s = theStack[:len(theStack)-1]
	return x, nil
}

type canonAtt []xml.Attr

func (att canonAtt) Len() int {
	return len(att)
}

func (att canonAtt) Swap(i, j int) {
	att[i], att[j] = att[j], att[i]
}

func (att canonAtt) Less(i, j int) bool {
	iName := att[i].Name.Local
	jName := att[j].Name.Local
	if iName == "xmlns" {
		return true
	}
	if jName == "xmlns" {
		return false
	}
	return att[i].Name.Local < att[j].Name.Local
}

func digestBase64(data string) string {
	return base64.StdEncoding.EncodeToString(digest(data))
}

func digest(data string) []byte {
	h := sha256.New()
	h.Write([]byte(data))
	return h.Sum(nil)
}

func ParseAndCanonicalizeXml(xmlstring string) (string, string, string, string, error) {

	// write xml string to a buffer
	var buffer, out bytes.Buffer
	writer := bufio.NewWriter(&buffer)
	writer.Write([]byte(xmlstring))
	writer.Flush()

	// read from the buffer
	decoder := xml.NewDecoder(bytes.NewReader(buffer.Bytes()))
	outWriter := bufio.NewWriter(&out)

	charData := ""
	tagStart := false
	stack := &stack{}

	digestValue := ""
	signatureValue := ""
	signatureTagStart := -1
	signatureTagEnd := -1
	signedinfoTagStart := -1
	signedinfoTagEnd := -1

	writeStartElement := func(writer io.Writer, start xml.StartElement) {
		fmt.Fprintf(writer, "<%s", start.Name.Local)
		sort.Sort(canonAtt(start.Attr))
		currentNs, err := stack.Top()
		if err != nil {
			// No namespaces yet declare ours
			fmt.Fprintf(writer, " %s=\"%s\"", "xmlns", start.Name.Space)
		} else {
			// Different namespace declare ours
			if currentNs != start.Name.Space {
				fmt.Fprintf(writer, " %s=\"%s\"", "xmlns", start.Name.Space)
			}
			// inhiret tag Signature's namespace for SignedInfo
			// just for conveniance...
			if start.Name.Local == SIGNEDINFO_TAG {
				fmt.Fprintf(writer, " %s=\"%s\"", "xmlns", SIGNEDINFO_XMLNS)
			}
		}

		stack.Push(start.Name.Space)
		for i := range start.Attr {
			if "xmlns" != start.Attr[i].Name.Local {
				fmt.Fprintf(writer, " %s=\"%s\"", start.Attr[i].Name.Local, start.Attr[i].Value)
			}
		}
		fmt.Fprint(writer, ">")
	}

	// parse xml token
	for {
		token, err := decoder.Token()
		if err != nil {
			break
		}

		switch t := token.(type) {
		case xml.StartElement:
			if t.Name.Local == SIGNATURE_TAG {
				// .<Signature
				outWriter.Flush()
				signatureTagStart = out.Len()
			} else if t.Name.Local == SIGNEDINFO_TAG {
				// .<SignedInfo
				outWriter.Flush()
				signedinfoTagStart = out.Len()
			}
			writeStartElement(outWriter, t)
			charData = ""
			tagStart = true

		case xml.EndElement:
			if charData != "" {
				outWriter.Write([]byte(charData))
				if t.Name.Local == DIGEST_VALUE_TAG {
					digestValue = charData
				}
				if t.Name.Local == SIGNATURE_VALUE_TAG {
					signatureValue = charData
				}
			}
			charData = ""
			tagStart = false

			stack.Pop()
			fmt.Fprintf(outWriter, "</%s>", t.Name.Local)

			if t.Name.Local == SIGNATURE_TAG {
				// </Signature>.
				outWriter.Flush()
				signatureTagEnd = out.Len()
			} else if t.Name.Local == SIGNEDINFO_TAG {
				// </SignedInfo>.
				outWriter.Flush()
				signedinfoTagEnd = out.Len()
			}

		case xml.CharData:
			if tagStart {
				charData = string(t)
			}
		}
	}

	// the whole xml
	outWriter.Flush()
	canonicalizeXmlBytes := out.Bytes()

	// ...<Signatrue><SignInfo>...</SignInfo></Signature>
	if signatureTagStart == -1 || signatureTagEnd == -1 || signedinfoTagStart == -1 || signedinfoTagEnd == -1 {
		return "", "", "", "", errors.New(fmt.Sprintf("can't find tag %s or %s", SIGNATURE_TAG, SIGNEDINFO_TAG))
	}
	if digestValue == "" {
		return "", "", "", "", errors.New("can't find digest value")
	}
	if signatureValue == "" {
		return "", "", "", "", errors.New("can't find signature value")
	}

	// extract SignInfo node
	signinfoNodeStr := string(canonicalizeXmlBytes[signedinfoTagStart:signedinfoTagEnd])
	// remove Signature node
	dataNodeStr := string(canonicalizeXmlBytes[:signatureTagStart]) + string(canonicalizeXmlBytes[signatureTagEnd:])

	return dataNodeStr, signinfoNodeStr, digestValue, signatureValue, nil
}

func main() {
	dataStr, signInfoStr, digestStr, signatureStr, err := ParseAndCanonicalizeXml(xmlstring)
	if err != nil {
		fmt.Printf("ParseAndCanonicalizeXml %s failed: %s\n", xmlstring, err.Error())
		return
	}
	fmt.Printf("--data: \n%s\n--signInfo:\n%s\n--digest:\n%s\n--signature:\n%s\n",
		dataStr, signInfoStr, digestStr, signatureStr)
	fmt.Printf("\n--calculated base64 digest: \n%s\n", digestBase64(dataStr))

	bytes, err := ioutil.ReadFile(certFile)
	if err != nil {
		fmt.Printf("read cert file failed: %s\n", err.Error())
		return
	}

	cert, err := MyParseCertificate(bytes)
	if err != nil {
		fmt.Printf("parse certificate failed: %s, cert: %v\n", err.Error(), cert)
		return
	}

	publickey := cert.PublicKey
	pub, ok := publickey.(*rsa.PublicKey)
	if !ok {
		fmt.Printf("invalid rsa publickey: %#v\n", publickey)
		return
	}

	signatureBytes, err := base64.StdEncoding.DecodeString(signatureStr)
	if err != nil {
		fmt.Printf("base64 decode signature failed: %s\n", err.Error())
		return
	}

	err = rsa.VerifyPKCS1v15(pub, crypto.SHA256, digest(signInfoStr), signatureBytes)
	if err != nil {
		fmt.Printf("rsa.VerifyPKCS1v15 failed: %s\n", err.Error())
		return
	}
	fmt.Printf("\nrsa verification passed!\n")
}

const certFile = "IapReceiptProduction.cer"

const xmlstring string = `
<?xml version="1.0"?>
<Receipt Version="1.0" CertificateId="A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD" xmlns="http://schemas.microsoft.com/windows/2012/store/receipt">
  <ProductReceipt PurchasePrice="$20.89" PurchaseDate="2012-11-30T21:32:07.096Z" Id="2f9c5c8f-3e1d-4fc7-a871-ac58f7e78053" AppId="3ec6cd9a-ca82-4d38-bfdf-ecafdb35a738" ProductId="Test" ProductType="Consumable" PublisherDeviceId="Test" MicrosoftProductId="59ef70aa-7099-4679-889e-f21919bfd2c6" />
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
      <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
      <Reference URI="">
        <Transforms>
          <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
        <DigestValue>FyFb1HGm+yeOIjt18M6TPD4Qzeu469vwDbQs7w72mdA=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>noct5CYBtRwBxVxkUeZIzeDyruLGVBqBMuFuBytpouPLACnQ5dbzdRvWX4XN67IUo0J2FW8DoYcMbf3sAS+PeKKV8SLnU+l8K1hWEbbbugHZezStTzwwkYcZuCTnAk7BYO0aiZWuXm9GiZGT9iyXsYtU1/u87L+llnVibU/m7gV8tD3vG0tVkjzV20C8666mHUsY/jxeq3ed7YY9CT0SDrh5PeL4ESaopBLcncHo/e6lcjyoKbO3e6YuIpsi8DVueeKNhpTlwa5yc0O3qzc5SGnT4Kbhj9NBEXf15/oTaLlg7lJhnQZ0mY+yR8vc4D0SkqD6e5Uc4u64hnu+g3Hphg==</SignatureValue>
  </Signature>
</Receipt>
`
<|endoftext|>


<commit_before><commit_msg>Do not fail on missing cluster-members<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"

	"github.com/codegangsta/cli"

	"github.com/cafebazaar/kupak/pkg/pak"
	"github.com/cafebazaar/kupak/pkg/util"
)

func paks(c *cli.Context) error {
	repoAddresses := make([]string, 0)
	if c.GlobalIsSet("repo") {
		repoAddresses = append(repoAddresses, c.GlobalString("repo"))
	} else {
		reposFileCreateIfNotExist()
		for _, repoEntry := range reposFileEntries() {
			trimmed := strings.TrimSpace(repoEntry)
			if len(trimmed) > 0 {
				repoAddresses = append(repoAddresses, trimmed)
			}
		}
		if len(repoAddresses) == 0 {
			repoAddresses = append(repoAddresses, "github.com/cafebazaar/paks")
		}
	}

	for _, repoAddress := range repoAddresses {
		repo, err := pak.RepoFromURL(repoAddress)
		if err != nil {
			return cli.NewExitError(fmt.Sprintf("can't fetch paks list: %v", err.Error()), -1)
		}
		fmt.Println("- Repository:", repoAddress)
		for i := range repo.Paks {
			fmt.Println("  - Name:", repo.Paks[i].Name)
			fmt.Println("    Version:", repo.Paks[i].Version)
			fmt.Println("    URL:", repo.Paks[i].URL)
			if len(repo.Paks[i].Tags) > 0 {
				fmt.Println("    Tags:", "["+strings.Join(repo.Paks[i].Tags, ", ")+"]")
			}
			fmt.Println("   ", strings.Trim(repo.Paks[i].Description, "\n"))
		}

	}
	return nil
}

func spec(c *cli.Context) error {
	pakURL := c.Args().First()
	if pakURL == "" {
		return cli.NewExitError("please specify the pak name", -1)
	}
	if strings.Index(pakURL, "/") == -1 &&
		!strings.HasSuffix(pakURL, ".json") &&
		!strings.HasSuffix(pakURL, ".yaml") {

		nameOfPakToCheck := pakURL

		repoAddresses := make([]string, 0)
		if c.GlobalIsSet("repo") {
			repoAddresses = append(repoAddresses, c.GlobalString("repo"))
		} else {
			reposFileCreateIfNotExist()
			for _, repoEntry := range reposFileEntries() {
				trimmed := strings.TrimSpace(repoEntry)
				if len(trimmed) > 0 {
					repoAddresses = append(repoAddresses, trimmed)
				}
			}
			if len(repoAddresses) == 0 {
				repoAddresses = append(repoAddresses, "github.com/cafebazaar/paks")
			}
		}

		for _, repoAddr := range repoAddresses {
			if len(repoAddr) > 0 {
				// TODO: change JoinURL
				repoPaks, err := pak.RepoFromURL(repoAddr)
				if err != nil {
					return cli.NewExitError(fmt.Sprintf("can't fetch the repo: %v", err.Error()), -1)
				}
				for _, pak := range repoPaks.Paks {
					if pak.Name == nameOfPakToCheck {
						pakURL = pak.URL
						if util.Relative(pakURL) {
							pakURL = util.JoinURL(repoAddr, pakURL)
						}
						specOfPakWithAbsoluteURLFromRepo(pakURL, repoAddr)
					}
				}
			}
		}
	} else {
		specOfPakWithAbsoluteURL(pakURL)
	}
	return nil
}

func specOfPakWithAbsoluteURLFromRepo(pakURL, repo string) error {
	p, err := pak.FromURL(pakURL)
	if err != nil {
		return cli.NewExitError(fmt.Sprintf("can't fetch the specified pak: %v", err.Error()), -1)
	}
	fmt.Println("-Repository:", repo)
	fmt.Println("  Name:", p.Name)
	fmt.Println("  Version:", p.Version)
	if len(p.Tags) > 0 {
		fmt.Println("  Tags:", "["+strings.Join(p.Tags, ", ")+"]")
	}
	fmt.Println(" ", strings.Trim(p.Description, "\n"))

	fmt.Println("\n  Properties:")
	for i := range p.Properties {
		property := p.Properties[i]
		fmt.Println("   - Name:", property.Name)
		fmt.Println("     Description:", strings.Trim(property.Description, "\n"))
		fmt.Println("     Type:", property.Type)
		if property.Default != nil {
			fmt.Println("     Default:", property.Default)
		}

	}
	return nil

}

func specOfPakWithAbsoluteURL(pakURL string) error {
	p, err := pak.FromURL(pakURL)
	if err != nil {
		return cli.NewExitError(fmt.Sprintf("can't fetch the specified pak: %v", err.Error()), -1)
	}
	fmt.Println("Name:", p.Name)
	fmt.Println("Version:", p.Version)
	if len(p.Tags) > 0 {
		fmt.Println("Tags:", "["+strings.Join(p.Tags, ", ")+"]")
	}
	fmt.Println(strings.Trim(p.Description, "\n"))

	fmt.Println("\nProperties:")
	for i := range p.Properties {
		property := p.Properties[i]
		fmt.Println(" - Name:", property.Name)
		fmt.Println("   Description:", strings.Trim(property.Description, "\n"))
		fmt.Println("   Type:", property.Type)
		if property.Default != nil {
			fmt.Println("   Default:", property.Default)
		}

	}
	return nil

}
<commit_msg>Bug fix<commit_after>package main

import (
	"fmt"
	"strings"

	"github.com/codegangsta/cli"

	"github.com/cafebazaar/kupak/pkg/pak"
	"github.com/cafebazaar/kupak/pkg/util"
)

func paks(c *cli.Context) error {
	repoAddresses := make([]string, 0)
	if c.GlobalIsSet("repo") {
		repoAddresses = append(repoAddresses, c.GlobalString("repo"))
	} else {
		reposFileCreateIfNotExist()
		for _, repoEntry := range reposFileNonEmptyEntries() {
			trimmed := strings.TrimSpace(repoEntry)
			if len(trimmed) > 0 {
				repoAddresses = append(repoAddresses, trimmed)
			}
		}
		if len(repoAddresses) == 0 {
			repoAddresses = append(repoAddresses, "github.com/cafebazaar/paks")
		}
	}

	for _, repoAddress := range repoAddresses {
		repo, err := pak.RepoFromURL(repoAddress)
		if err != nil {
			return cli.NewExitError(fmt.Sprintf("can't fetch paks list: %v", err.Error()), -1)
		}
		fmt.Println("- Repository:", repoAddress)
		for i := range repo.Paks {
			fmt.Println("  - Name:", repo.Paks[i].Name)
			fmt.Println("    Version:", repo.Paks[i].Version)
			fmt.Println("    URL:", repo.Paks[i].URL)
			if len(repo.Paks[i].Tags) > 0 {
				fmt.Println("    Tags:", "["+strings.Join(repo.Paks[i].Tags, ", ")+"]")
			}
			fmt.Println("   ", strings.Trim(repo.Paks[i].Description, "\n"))
		}

	}
	return nil
}

func spec(c *cli.Context) error {
	pakURL := c.Args().First()
	if pakURL == "" {
		return cli.NewExitError("please specify the pak name", -1)
	}
	if strings.Index(pakURL, "/") == -1 &&
		!strings.HasSuffix(pakURL, ".json") &&
		!strings.HasSuffix(pakURL, ".yaml") {

		nameOfPakToCheck := pakURL

		repoAddresses := make([]string, 0)
		if c.GlobalIsSet("repo") {
			repoAddresses = append(repoAddresses, c.GlobalString("repo"))
		} else {
			reposFileCreateIfNotExist()
			for _, repoEntry := range reposFileNonEmptyEntries() {
				trimmed := strings.TrimSpace(repoEntry)
				if len(trimmed) > 0 {
					repoAddresses = append(repoAddresses, trimmed)
				}
			}
			if len(repoAddresses) == 0 {
				repoAddresses = append(repoAddresses, "github.com/cafebazaar/paks")
			}
		}

		for _, repoAddr := range repoAddresses {
			if len(repoAddr) > 0 {
				// TODO: change JoinURL
				repoPaks, err := pak.RepoFromURL(repoAddr)
				if err != nil {
					return cli.NewExitError(fmt.Sprintf("can't fetch the repo: %v", err.Error()), -1)
				}
				for _, pak := range repoPaks.Paks {
					if pak.Name == nameOfPakToCheck {
						pakURL = pak.URL
						if util.Relative(pakURL) {
							pakURL = util.JoinURL(repoAddr, pakURL)
						}
						specOfPakWithAbsoluteURLFromRepo(pakURL, repoAddr)
					}
				}
			}
		}
	} else {
		specOfPakWithAbsoluteURL(pakURL)
	}
	return nil
}

func specOfPakWithAbsoluteURLFromRepo(pakURL, repo string) error {
	p, err := pak.FromURL(pakURL)
	if err != nil {
		return cli.NewExitError(fmt.Sprintf("can't fetch the specified pak: %v", err.Error()), -1)
	}
	fmt.Println("-Repository:", repo)
	fmt.Println("  Name:", p.Name)
	fmt.Println("  Version:", p.Version)
	if len(p.Tags) > 0 {
		fmt.Println("  Tags:", "["+strings.Join(p.Tags, ", ")+"]")
	}
	fmt.Println(" ", strings.Trim(p.Description, "\n"))

	fmt.Println("\n  Properties:")
	for i := range p.Properties {
		property := p.Properties[i]
		fmt.Println("   - Name:", property.Name)
		fmt.Println("     Description:", strings.Trim(property.Description, "\n"))
		fmt.Println("     Type:", property.Type)
		if property.Default != nil {
			fmt.Println("     Default:", property.Default)
		}

	}
	return nil

}

func specOfPakWithAbsoluteURL(pakURL string) error {
	p, err := pak.FromURL(pakURL)
	if err != nil {
		return cli.NewExitError(fmt.Sprintf("can't fetch the specified pak: %v", err.Error()), -1)
	}
	fmt.Println("Name:", p.Name)
	fmt.Println("Version:", p.Version)
	if len(p.Tags) > 0 {
		fmt.Println("Tags:", "["+strings.Join(p.Tags, ", ")+"]")
	}
	fmt.Println(strings.Trim(p.Description, "\n"))

	fmt.Println("\nProperties:")
	for i := range p.Properties {
		property := p.Properties[i]
		fmt.Println(" - Name:", property.Name)
		fmt.Println("   Description:", strings.Trim(property.Description, "\n"))
		fmt.Println("   Type:", property.Type)
		if property.Default != nil {
			fmt.Println("   Default:", property.Default)
		}

	}
	return nil

}
<|endoftext|>


<commit_before>package enmime

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	//"mime/multipart"
	//"mime/quotedprintable"
	"net/textproto"
	"strings"

	"github.com/cention-sany/mime"
	"github.com/cention-sany/mime/multipart"
	"github.com/cention-sany/mime/quotedprintable"
)

// MIMEPart is the primary interface enmine clients will use.  Each MIMEPart represents
// a node in the MIME multipart tree.  The Content-Type, Disposition and File Name are
// parsed out of the header for easier access.
//
// TODO Content should probably be a reader so that it does not need to be stored in
// memory.
type MIMEPart interface {
	Parent() MIMEPart             // Parent of this part (can be nil)
	FirstChild() MIMEPart         // First (top most) child of this part
	NextSibling() MIMEPart        // Next sibling of this part
	Header() textproto.MIMEHeader // Header as parsed by textproto package
	ContentType() string          // Content-Type header without parameters
	Disposition() string          // Content-Disposition header without parameters
	FileName() string             // File Name from disposition or type header
	Charset() string              // Content Charset
	Content() []byte              // Decoded content of this part (can be empty)
}

// memMIMEPart is an in-memory implementation of the MIMEPart interface.  It will likely
// choke on huge attachments.
type memMIMEPart struct {
	parent      MIMEPart
	firstChild  MIMEPart
	nextSibling MIMEPart
	header      textproto.MIMEHeader
	contentType string
	disposition string
	fileName    string
	charset     string
	content     []byte
}

// NewMIMEPart creates a new memMIMEPart object.  It does not update the parents FirstChild
// attribute.
func NewMIMEPart(parent MIMEPart, contentType string) *memMIMEPart {
	return &memMIMEPart{parent: parent, contentType: contentType}
}

// Parent of this part (can be nil)
func (p *memMIMEPart) Parent() MIMEPart {
	return p.parent
}

// First (top most) child of this part
func (p *memMIMEPart) FirstChild() MIMEPart {
	return p.firstChild
}

// Next sibling of this part
func (p *memMIMEPart) NextSibling() MIMEPart {
	return p.nextSibling
}

// Header as parsed by textproto package
func (p *memMIMEPart) Header() textproto.MIMEHeader {
	return p.header
}

// Content-Type header without parameters
func (p *memMIMEPart) ContentType() string {
	return p.contentType
}

// Content-Disposition header without parameters
func (p *memMIMEPart) Disposition() string {
	return p.disposition
}

// File Name from disposition or type header
func (p *memMIMEPart) FileName() string {
	return p.fileName
}

// Content charset
func (p *memMIMEPart) Charset() string {
	return p.charset
}

// Decoded content of this part (can be empty)
func (p *memMIMEPart) Content() []byte {
	return p.content
}

// ParseMIME reads a MIME document from the provided reader and parses it into
// tree of MIMEPart objects.
func ParseMIME(reader *bufio.Reader) (MIMEPart, error) {
	tr := textproto.NewReader(reader)
	header, err := tr.ReadMIMEHeader()
	if err != nil {
		return nil, err
	}
	mediatype, params, err := mime.ParseMediaType(header.Get("Content-Type"))
	if err != nil && err != mime.BuggyMediaType {
		return nil, err
	}
	root := &memMIMEPart{header: header, contentType: mediatype}

	if strings.HasPrefix(mediatype, "multipart/") {
		boundary := params["boundary"]
		err = parseParts(root, reader, boundary)
		if err != nil {
			return nil, err
		}
	} else {
		// Content is text or data, decode it
		content, err := decodeSection(header.Get("Content-Transfer-Encoding"), reader)
		if err != nil {
			return nil, err
		}
		root.content = content
	}

	return root, nil
}

// parseParts recursively parses a mime multipart document.
func parseParts(parent *memMIMEPart, reader io.Reader, boundary string) error {
	var prevSibling *memMIMEPart

	// Loop over MIME parts
	mr := multipart.NewReader(reader, boundary)
	for {
		// mrp is golang's built in mime-part
		mrp, err := mr.NextPart()
		if err != nil {
			if err == io.EOF {
				// This is a clean end-of-message signal
				break
			}
			return err
		}
		if len(mrp.Header) == 0 {
			// Empty header probably means the part didn't using the correct trailing "--"
			// syntax to close its boundary.  We will let this slide if this this the
			// last MIME part.
			if _, err := mr.NextPart(); err != nil {
				if err == io.EOF || strings.HasSuffix(err.Error(), "EOF") {
					// This is what we were hoping for
					break
				} else {
					return fmt.Errorf("Error at boundary %v: %v", boundary, err)
				}
			}

			return fmt.Errorf("Empty header at boundary %v", boundary)
		}
		ctype := mrp.Header.Get("Content-Type")
		if ctype == "" {
			return fmt.Errorf("Missing Content-Type at boundary %v", boundary)
		}
		mediatype, mparams, err := mime.ParseMediaType(ctype)
		if err != nil && err != mime.BuggyMediaType {
			return err
		}

		// Insert ourselves into tree, p is enmime's mime-part
		p := NewMIMEPart(parent, mediatype)
		p.header = mrp.Header
		if prevSibling != nil {
			prevSibling.nextSibling = p
		} else {
			parent.firstChild = p
		}
		prevSibling = p

		// Figure out our disposition, filename
		disposition, dparams, err := mime.ParseMediaType(mrp.Header.Get("Content-Disposition"))
		if err == nil || err == mime.BuggyMediaType {
			// Disposition is optional
			p.disposition = disposition
			p.fileName = DecodeHeader(dparams["filename"])
		}
		if p.fileName == "" && mparams["name"] != "" {
			p.fileName = DecodeHeader(mparams["name"])
		}
		if p.fileName == "" && mparams["file"] != "" {
			p.fileName = DecodeHeader(mparams["file"])
		}
		if p.charset == "" {
			p.charset = mparams["charset"]
		}

		boundary := mparams["boundary"]
		if boundary != "" {
			// Content is another multipart
			err = parseParts(p, mrp, boundary)
			if err != nil {
				return err
			}
		} else {
			// Content is text or data, decode it
			data, err := decodeSection(mrp.Header.Get("Content-Transfer-Encoding"), mrp)
			if err != nil {
				return err
			}
			p.content = data
		}
	}

	return nil
}

// decodeSection attempts to decode the data from reader using the algorithm listed in
// the Content-Transfer-Encoding header, returning the raw data if it does not known
// the encoding type.
func decodeSection(encoding string, reader io.Reader) ([]byte, error) {
	// Default is to just read input into bytes
	decoder := reader

	switch strings.ToLower(encoding) {
	case "quoted-printable":
		decoder = quotedprintable.NewReader(reader)
	case "base64":
		// cleaner := NewBase64Cleaner(reader)
		// decoder = base64.NewDecoder(base64.StdEncoding, cleaner)
		decoder = NewBase64Combiner(reader)
	}

	// Read bytes into buffer
	buf := new(bytes.Buffer)
	_, err := buf.ReadFrom(decoder)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
<commit_msg>Allow to parse MIME body without any header field<commit_after>package enmime

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	//"mime/multipart"
	//"mime/quotedprintable"
	"net/textproto"
	"strings"

	"github.com/cention-sany/mime"
	"github.com/cention-sany/mime/multipart"
	"github.com/cention-sany/mime/quotedprintable"
)

// MIMEPart is the primary interface enmine clients will use.  Each MIMEPart represents
// a node in the MIME multipart tree.  The Content-Type, Disposition and File Name are
// parsed out of the header for easier access.
//
// TODO Content should probably be a reader so that it does not need to be stored in
// memory.
type MIMEPart interface {
	Parent() MIMEPart             // Parent of this part (can be nil)
	FirstChild() MIMEPart         // First (top most) child of this part
	NextSibling() MIMEPart        // Next sibling of this part
	Header() textproto.MIMEHeader // Header as parsed by textproto package
	ContentType() string          // Content-Type header without parameters
	Disposition() string          // Content-Disposition header without parameters
	FileName() string             // File Name from disposition or type header
	Charset() string              // Content Charset
	Content() []byte              // Decoded content of this part (can be empty)
}

// memMIMEPart is an in-memory implementation of the MIMEPart interface.  It will likely
// choke on huge attachments.
type memMIMEPart struct {
	parent      MIMEPart
	firstChild  MIMEPart
	nextSibling MIMEPart
	header      textproto.MIMEHeader
	contentType string
	disposition string
	fileName    string
	charset     string
	content     []byte
}

// NewMIMEPart creates a new memMIMEPart object.  It does not update the parents FirstChild
// attribute.
func NewMIMEPart(parent MIMEPart, contentType string) *memMIMEPart {
	return &memMIMEPart{parent: parent, contentType: contentType}
}

// Parent of this part (can be nil)
func (p *memMIMEPart) Parent() MIMEPart {
	return p.parent
}

// First (top most) child of this part
func (p *memMIMEPart) FirstChild() MIMEPart {
	return p.firstChild
}

// Next sibling of this part
func (p *memMIMEPart) NextSibling() MIMEPart {
	return p.nextSibling
}

// Header as parsed by textproto package
func (p *memMIMEPart) Header() textproto.MIMEHeader {
	return p.header
}

// Content-Type header without parameters
func (p *memMIMEPart) ContentType() string {
	return p.contentType
}

// Content-Disposition header without parameters
func (p *memMIMEPart) Disposition() string {
	return p.disposition
}

// File Name from disposition or type header
func (p *memMIMEPart) FileName() string {
	return p.fileName
}

// Content charset
func (p *memMIMEPart) Charset() string {
	return p.charset
}

// Decoded content of this part (can be empty)
func (p *memMIMEPart) Content() []byte {
	return p.content
}

// ParseMIME reads a MIME document from the provided reader and parses it into
// tree of MIMEPart objects.
func ParseMIME(reader *bufio.Reader) (MIMEPart, error) {
	tr := textproto.NewReader(reader)
	header, err := tr.ReadMIMEHeader()
	if err != nil {
		return nil, err
	}
	mediatype, params, err := mime.ParseMediaType(header.Get("Content-Type"))
	if err != nil && err != mime.BuggyMediaType {
		return nil, err
	}
	root := &memMIMEPart{header: header, contentType: mediatype}

	if strings.HasPrefix(mediatype, "multipart/") {
		boundary := params["boundary"]
		err = parseParts(root, reader, boundary)
		if err != nil {
			return nil, err
		}
	} else {
		// Content is text or data, decode it
		content, err := decodeSection(header.Get("Content-Transfer-Encoding"), reader)
		if err != nil {
			return nil, err
		}
		root.content = content
	}

	return root, nil
}

const default_content_type = "text/plain; charset=US-ASCII"

// parseParts recursively parses a mime multipart document.
func parseParts(parent *memMIMEPart, reader io.Reader, boundary string) error {
	var prevSibling *memMIMEPart

	// Loop over MIME parts
	mr := multipart.NewReader(reader, boundary)
	for {
		// mrp is golang's built in mime-part
		mrp, err := mr.NextPart()
		if err != nil {
			if err == io.EOF {
				// This is a clean end-of-message signal
				break
			}
			return err
		}
		if len(mrp.Header) == 0 {
			// Empty header probably means the part didn't using the correct trailing "--"
			// syntax to close its boundary.  We will let this slide if this this the
			// last MIME part.
			if _, err := mr.NextPart(); err != nil {
				if err == io.EOF || strings.HasSuffix(err.Error(), "EOF") {
					// This is what we were hoping for
					break
				} else {
					return fmt.Errorf("Error at boundary %v: %v", boundary, err)
				}
			}
			// empty header field inside mime part body should not treat as error
			//return fmt.Errorf("Empty header at boundary %v", boundary)
			mrp.Header.Add("Content-Type", default_content_type)
		}
		ctype := mrp.Header.Get("Content-Type")
		if ctype == "" {
			// can not find Content-Type header does not mean error
			//return fmt.Errorf("Missing Content-Type at boundary %v", boundary)
			mrp.Header.Add("Content-Type", default_content_type)
		}
		mediatype, mparams, err := mime.ParseMediaType(ctype)
		if err != nil && err != mime.BuggyMediaType {
			return err
		}

		// Insert ourselves into tree, p is enmime's mime-part
		p := NewMIMEPart(parent, mediatype)
		p.header = mrp.Header
		if prevSibling != nil {
			prevSibling.nextSibling = p
		} else {
			parent.firstChild = p
		}
		prevSibling = p

		// Figure out our disposition, filename
		disposition, dparams, err := mime.ParseMediaType(mrp.Header.Get("Content-Disposition"))
		if err == nil || err == mime.BuggyMediaType {
			// Disposition is optional
			p.disposition = disposition
			p.fileName = DecodeHeader(dparams["filename"])
		}
		if p.fileName == "" && mparams["name"] != "" {
			p.fileName = DecodeHeader(mparams["name"])
		}
		if p.fileName == "" && mparams["file"] != "" {
			p.fileName = DecodeHeader(mparams["file"])
		}
		if p.charset == "" {
			p.charset = mparams["charset"]
		}

		boundary := mparams["boundary"]
		if boundary != "" {
			// Content is another multipart
			err = parseParts(p, mrp, boundary)
			if err != nil {
				return err
			}
		} else {
			// Content is text or data, decode it
			data, err := decodeSection(mrp.Header.Get("Content-Transfer-Encoding"), mrp)
			if err != nil {
				return err
			}
			p.content = data
		}
	}

	return nil
}

// decodeSection attempts to decode the data from reader using the algorithm listed in
// the Content-Transfer-Encoding header, returning the raw data if it does not known
// the encoding type.
func decodeSection(encoding string, reader io.Reader) ([]byte, error) {
	// Default is to just read input into bytes
	decoder := reader

	switch strings.ToLower(encoding) {
	case "quoted-printable":
		decoder = quotedprintable.NewReader(reader)
	case "base64":
		// cleaner := NewBase64Cleaner(reader)
		// decoder = base64.NewDecoder(base64.StdEncoding, cleaner)
		decoder = NewBase64Combiner(reader)
	}

	// Read bytes into buffer
	buf := new(bytes.Buffer)
	_, err := buf.ReadFrom(decoder)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
<|endoftext|>


<commit_before><commit_msg>psi: New Section.CRC method.<commit_after><|endoftext|>


<commit_before><commit_msg>Switch group rank to org<commit_after><|endoftext|>


<commit_before><commit_msg>Move testutil package to top-level<commit_after><|endoftext|>


<commit_before>package restrictedendpoints

import (
	"context"
	"fmt"
	"io"
	"net"
	"reflect"

	"k8s.io/apiserver/pkg/admission"
	"k8s.io/apiserver/pkg/admission/initializer"
	"k8s.io/apiserver/pkg/authorization/authorizer"
	"k8s.io/klog/v2"
	kapi "k8s.io/kubernetes/pkg/apis/core"

	"github.com/openshift/library-go/pkg/config/helpers"
	"k8s.io/kubernetes/openshift-kube-apiserver/admission/network/apis/restrictedendpoints"
	v1 "k8s.io/kubernetes/openshift-kube-apiserver/admission/network/apis/restrictedendpoints/v1"
)

const RestrictedEndpointsPluginName = "network.openshift.io/RestrictedEndpointsAdmission"

func RegisterRestrictedEndpoints(plugins *admission.Plugins) {
	plugins.Register(RestrictedEndpointsPluginName,
		func(config io.Reader) (admission.Interface, error) {
			pluginConfig, err := readConfig(config)
			if err != nil {
				return nil, err
			}
			if pluginConfig == nil {
				klog.Infof("Admission plugin %q is not configured so it will be disabled.", RestrictedEndpointsPluginName)
				return nil, nil
			}
			restrictedNetworks, err := ParseSimpleCIDRRules(pluginConfig.RestrictedCIDRs)
			if err != nil {
				// should have been caught with validation
				return nil, err
			}

			return NewRestrictedEndpointsAdmission(restrictedNetworks), nil
		})
}

func readConfig(reader io.Reader) (*restrictedendpoints.RestrictedEndpointsAdmissionConfig, error) {
	obj, err := helpers.ReadYAMLToInternal(reader, restrictedendpoints.Install, v1.Install)
	if err != nil {
		return nil, err
	}
	if obj == nil {
		return nil, nil
	}
	config, ok := obj.(*restrictedendpoints.RestrictedEndpointsAdmissionConfig)
	if !ok {
		return nil, fmt.Errorf("unexpected config object: %#v", obj)
	}
	// No validation needed since config is just list of strings
	return config, nil
}

type restrictedEndpointsAdmission struct {
	*admission.Handler

	authorizer         authorizer.Authorizer
	restrictedNetworks []*net.IPNet
}

var _ = initializer.WantsAuthorizer(&restrictedEndpointsAdmission{})
var _ = admission.ValidationInterface(&restrictedEndpointsAdmission{})

// ParseSimpleCIDRRules parses a list of CIDR strings
func ParseSimpleCIDRRules(rules []string) (networks []*net.IPNet, err error) {
	for _, s := range rules {
		_, cidr, err := net.ParseCIDR(s)
		if err != nil {
			return nil, err
		}
		networks = append(networks, cidr)
	}
	return networks, nil
}

// NewRestrictedEndpointsAdmission creates a new endpoints admission plugin.
func NewRestrictedEndpointsAdmission(restrictedNetworks []*net.IPNet) *restrictedEndpointsAdmission {
	return &restrictedEndpointsAdmission{
		Handler:            admission.NewHandler(admission.Create, admission.Update),
		restrictedNetworks: restrictedNetworks,
	}
}

func (r *restrictedEndpointsAdmission) SetAuthorizer(a authorizer.Authorizer) {
	r.authorizer = a
}

func (r *restrictedEndpointsAdmission) ValidateInitialization() error {
	if r.authorizer == nil {
		return fmt.Errorf("missing authorizer")
	}
	return nil
}

var (
	defaultRestrictedPorts = []kapi.EndpointPort{
		// MCS ports
		{Protocol: kapi.ProtocolTCP, Port: 22623},
		{Protocol: kapi.ProtocolTCP, Port: 22624},
	}
	defaultRestrictedNetworks = []*net.IPNet{
		// IPv4 link-local range 169.254.0.0/16 (including cloud metadata IP)
		{IP: net.ParseIP("169.254.0.0"), Mask: net.CIDRMask(16, 32)},
	}
)

func (r *restrictedEndpointsAdmission) findRestrictedIP(ep *kapi.Endpoints, restricted []*net.IPNet) error {
	for _, subset := range ep.Subsets {
		for _, addr := range subset.Addresses {
			ip := net.ParseIP(addr.IP)
			if ip == nil {
				continue
			}
			for _, net := range restricted {
				if net.Contains(ip) {
					return fmt.Errorf("endpoint address %s is not allowed", addr.IP)
				}
			}
		}
	}
	return nil
}

func (r *restrictedEndpointsAdmission) findRestrictedPort(ep *kapi.Endpoints, restricted []kapi.EndpointPort) error {
	for _, subset := range ep.Subsets {
		for _, port := range subset.Ports {
			for _, restricted := range restricted {
				if port.Protocol == restricted.Protocol && port.Port == restricted.Port {
					return fmt.Errorf("endpoint port %s:%d is not allowed", string(port.Protocol), port.Port)
				}
			}
		}
	}
	return nil
}

func (r *restrictedEndpointsAdmission) checkAccess(ctx context.Context, attr admission.Attributes) (bool, error) {
	authzAttr := authorizer.AttributesRecord{
		User:            attr.GetUserInfo(),
		Verb:            "create",
		Namespace:       attr.GetNamespace(),
		Resource:        "endpoints",
		Subresource:     "restricted",
		APIGroup:        kapi.GroupName,
		Name:            attr.GetName(),
		ResourceRequest: true,
	}
	authorized, _, err := r.authorizer.Authorize(ctx, authzAttr)
	return authorized == authorizer.DecisionAllow, err
}

// Admit determines if the endpoints object should be admitted
func (r *restrictedEndpointsAdmission) Validate(ctx context.Context, a admission.Attributes, _ admission.ObjectInterfaces) error {
	if a.GetResource().GroupResource() != kapi.Resource("endpoints") {
		return nil
	}
	ep, ok := a.GetObject().(*kapi.Endpoints)
	if !ok {
		return nil
	}
	old, ok := a.GetOldObject().(*kapi.Endpoints)
	if ok && reflect.DeepEqual(ep.Subsets, old.Subsets) {
		return nil
	}

	restrictedErr := r.findRestrictedIP(ep, r.restrictedNetworks)
	if restrictedErr == nil {
		restrictedErr = r.findRestrictedIP(ep, defaultRestrictedNetworks)
	}
	if restrictedErr == nil {
		restrictedErr = r.findRestrictedPort(ep, defaultRestrictedPorts)
	}
	if restrictedErr == nil {
		return nil
	}

	allow, err := r.checkAccess(ctx, a)
	if err != nil {
		return err
	}
	if !allow {
		return admission.NewForbidden(a, restrictedErr)
	}
	return nil
}
<commit_msg>UPSTREAM: <carry>: Make RestrictedEndpointsAdmission check NotReadyAddresses<commit_after>package restrictedendpoints

import (
	"context"
	"fmt"
	"io"
	"net"
	"reflect"

	"k8s.io/apiserver/pkg/admission"
	"k8s.io/apiserver/pkg/admission/initializer"
	"k8s.io/apiserver/pkg/authorization/authorizer"
	"k8s.io/klog/v2"
	kapi "k8s.io/kubernetes/pkg/apis/core"

	"github.com/openshift/library-go/pkg/config/helpers"
	"k8s.io/kubernetes/openshift-kube-apiserver/admission/network/apis/restrictedendpoints"
	v1 "k8s.io/kubernetes/openshift-kube-apiserver/admission/network/apis/restrictedendpoints/v1"
)

const RestrictedEndpointsPluginName = "network.openshift.io/RestrictedEndpointsAdmission"

func RegisterRestrictedEndpoints(plugins *admission.Plugins) {
	plugins.Register(RestrictedEndpointsPluginName,
		func(config io.Reader) (admission.Interface, error) {
			pluginConfig, err := readConfig(config)
			if err != nil {
				return nil, err
			}
			if pluginConfig == nil {
				klog.Infof("Admission plugin %q is not configured so it will be disabled.", RestrictedEndpointsPluginName)
				return nil, nil
			}
			restrictedNetworks, err := ParseSimpleCIDRRules(pluginConfig.RestrictedCIDRs)
			if err != nil {
				// should have been caught with validation
				return nil, err
			}

			return NewRestrictedEndpointsAdmission(restrictedNetworks), nil
		})
}

func readConfig(reader io.Reader) (*restrictedendpoints.RestrictedEndpointsAdmissionConfig, error) {
	obj, err := helpers.ReadYAMLToInternal(reader, restrictedendpoints.Install, v1.Install)
	if err != nil {
		return nil, err
	}
	if obj == nil {
		return nil, nil
	}
	config, ok := obj.(*restrictedendpoints.RestrictedEndpointsAdmissionConfig)
	if !ok {
		return nil, fmt.Errorf("unexpected config object: %#v", obj)
	}
	// No validation needed since config is just list of strings
	return config, nil
}

type restrictedEndpointsAdmission struct {
	*admission.Handler

	authorizer         authorizer.Authorizer
	restrictedNetworks []*net.IPNet
}

var _ = initializer.WantsAuthorizer(&restrictedEndpointsAdmission{})
var _ = admission.ValidationInterface(&restrictedEndpointsAdmission{})

// ParseSimpleCIDRRules parses a list of CIDR strings
func ParseSimpleCIDRRules(rules []string) (networks []*net.IPNet, err error) {
	for _, s := range rules {
		_, cidr, err := net.ParseCIDR(s)
		if err != nil {
			return nil, err
		}
		networks = append(networks, cidr)
	}
	return networks, nil
}

// NewRestrictedEndpointsAdmission creates a new endpoints admission plugin.
func NewRestrictedEndpointsAdmission(restrictedNetworks []*net.IPNet) *restrictedEndpointsAdmission {
	return &restrictedEndpointsAdmission{
		Handler:            admission.NewHandler(admission.Create, admission.Update),
		restrictedNetworks: restrictedNetworks,
	}
}

func (r *restrictedEndpointsAdmission) SetAuthorizer(a authorizer.Authorizer) {
	r.authorizer = a
}

func (r *restrictedEndpointsAdmission) ValidateInitialization() error {
	if r.authorizer == nil {
		return fmt.Errorf("missing authorizer")
	}
	return nil
}

var (
	defaultRestrictedPorts = []kapi.EndpointPort{
		// MCS ports
		{Protocol: kapi.ProtocolTCP, Port: 22623},
		{Protocol: kapi.ProtocolTCP, Port: 22624},
	}
	defaultRestrictedNetworks = []*net.IPNet{
		// IPv4 link-local range 169.254.0.0/16 (including cloud metadata IP)
		{IP: net.ParseIP("169.254.0.0"), Mask: net.CIDRMask(16, 32)},
	}
)

func checkRestrictedIP(ipString string, restricted []*net.IPNet) error {
	ip := net.ParseIP(ipString)
	if ip == nil {
		return nil
	}
	for _, net := range restricted {
		if net.Contains(ip) {
			return fmt.Errorf("endpoint address %s is not allowed", ipString)
		}
	}
	return nil
}

func checkRestrictedPort(protocol kapi.Protocol, port int32, restricted []kapi.EndpointPort) error {
	for _, rport := range restricted {
		if protocol == rport.Protocol && port == rport.Port {
			return fmt.Errorf("endpoint port %s:%d is not allowed", protocol, port)
		}
	}
	return nil
}

func (r *restrictedEndpointsAdmission) findRestrictedIP(ep *kapi.Endpoints, restricted []*net.IPNet) error {
	for _, subset := range ep.Subsets {
		for _, addr := range subset.Addresses {
			if err := checkRestrictedIP(addr.IP, restricted); err != nil {
				return err
			}
		}
		for _, addr := range subset.NotReadyAddresses {
			if err := checkRestrictedIP(addr.IP, restricted); err != nil {
				return err
			}
		}
	}
	return nil
}

func (r *restrictedEndpointsAdmission) findRestrictedPort(ep *kapi.Endpoints, restricted []kapi.EndpointPort) error {
	for _, subset := range ep.Subsets {
		for _, port := range subset.Ports {
			if err := checkRestrictedPort(port.Protocol, port.Port, restricted); err != nil {
				return err
			}
		}
	}
	return nil
}

func (r *restrictedEndpointsAdmission) checkAccess(ctx context.Context, attr admission.Attributes) (bool, error) {
	authzAttr := authorizer.AttributesRecord{
		User:            attr.GetUserInfo(),
		Verb:            "create",
		Namespace:       attr.GetNamespace(),
		Resource:        "endpoints",
		Subresource:     "restricted",
		APIGroup:        kapi.GroupName,
		Name:            attr.GetName(),
		ResourceRequest: true,
	}
	authorized, _, err := r.authorizer.Authorize(ctx, authzAttr)
	return authorized == authorizer.DecisionAllow, err
}

// Admit determines if the endpoints object should be admitted
func (r *restrictedEndpointsAdmission) Validate(ctx context.Context, a admission.Attributes, _ admission.ObjectInterfaces) error {
	if a.GetResource().GroupResource() != kapi.Resource("endpoints") {
		return nil
	}
	ep, ok := a.GetObject().(*kapi.Endpoints)
	if !ok {
		return nil
	}
	old, ok := a.GetOldObject().(*kapi.Endpoints)
	if ok && reflect.DeepEqual(ep.Subsets, old.Subsets) {
		return nil
	}

	restrictedErr := r.findRestrictedIP(ep, r.restrictedNetworks)
	if restrictedErr == nil {
		restrictedErr = r.findRestrictedIP(ep, defaultRestrictedNetworks)
	}
	if restrictedErr == nil {
		restrictedErr = r.findRestrictedPort(ep, defaultRestrictedPorts)
	}
	if restrictedErr == nil {
		return nil
	}

	allow, err := r.checkAccess(ctx, a)
	if err != nil {
		return err
	}
	if !allow {
		return admission.NewForbidden(a, restrictedErr)
	}
	return nil
}
<|endoftext|>


<commit_before>package zk

import (
	"strings"
	"time"
)

type Config struct {
	Name           string
	ZkAddrs        string
	SessionTimeout time.Duration
	PanicOnError   bool
}

func DefaultConfig(name, addrs string) *Config {
	return &Config{
		Name:           name,
		ZkAddrs:        addrs,
		SessionTimeout: DefaultZkSessionTimeout(),
		PanicOnError:   false,
	}
}

func (this *Config) ZkServers() []string {
	return strings.Split(this.ZkAddrs, ",")
}

func DefaultZkSessionTimeout() time.Duration {
	return time.Minute * 5
}
<commit_msg>default zk session timeout is 20 because tickTime=2s<commit_after>package zk

import (
	"strings"
	"time"
)

type Config struct {
	Name           string
	ZkAddrs        string
	SessionTimeout time.Duration
	PanicOnError   bool
}

func DefaultConfig(name, addrs string) *Config {
	return &Config{
		Name:           name,
		ZkAddrs:        addrs,
		SessionTimeout: DefaultZkSessionTimeout(),
		PanicOnError:   false,
	}
}

func (this *Config) ZkServers() []string {
	return strings.Split(this.ZkAddrs, ",")
}

func DefaultZkSessionTimeout() time.Duration {
	// online zk tickTime=2000
	return time.Second * 20
}
<|endoftext|>


<commit_before><commit_msg>optimize to clone of schema<commit_after><|endoftext|>


<commit_before><commit_msg>Simplified options<commit_after><|endoftext|>


<commit_before>// +build windows

package mpwindowsprocessstats

import (
	"flag"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strconv"

	"github.com/StackExchange/wmi"
	mp "github.com/mackerelio/go-mackerel-plugin-helper"
	"github.com/mackerelio/golib/logging"
)

var logger = logging.GetLogger("metrics.plugin.windows-process-stats")

type Win32_PerfFormattedData_PerfProc_Process struct {
	ElapsedTime          uint64
	Name                 string
	IDProcess            uint32
	PercentProcessorTime uint64
	WorkingSet           uint64
}

type WindowsProcessStatsPlugin struct {
	Process     string
	MetricLabel string
}

func getProcesses(processName string) ([]Win32_PerfFormattedData_PerfProc_Process, error) {
	var procs []Win32_PerfFormattedData_PerfProc_Process

	q := wmi.CreateQuery(&procs, "WHERE Name like '"+processName+"%'")
	if err := wmi.Query(q, &procs); err != nil {
		return procs, err
	}

	sort.Slice(procs, func(i, j int) bool {
		return procs[i].IDProcess < procs[j].IDProcess
	})
	return procs, nil
}

// FetchMetrics interface for mackerelplugin
func (m WindowsProcessStatsPlugin) FetchMetrics() (map[string]interface{}, error) {
	procs, err := getProcesses(m.Process)
	if err != nil {
		return nil, err
	}
	stat := make(map[string]interface{})
	prefix := m.MetricLabel
	var re = regexp.MustCompile(`#[0-9]+$`)
	for k, v := range procs {
		name := re.ReplaceAllString(v.Name, "")
		processName := name + "_" + strconv.Itoa(k)
		metricNameCPU := prefix + "-windows-process-stats.cpu." + processName + ".cpu"
		metricNameMemory := prefix + "-windows-process-stats.memory." + processName + ".working_set"
		stat[metricNameCPU] = v.PercentProcessorTime
		stat[metricNameMemory] = v.WorkingSet
	}

	return stat, nil
}

// GraphDefinition interface for mackerelplugin
func (m WindowsProcessStatsPlugin) GraphDefinition() map[string](mp.Graphs) {
	prefix := m.MetricLabel
	return map[string](mp.Graphs){
		fmt.Sprintf("%s-windows-process-stats.cpu.#", prefix): mp.Graphs{
			Label: fmt.Sprintf("%s Windows Process Stats CPU", prefix),
			Unit:  "percentage",
			Metrics: []mp.Metrics{
				{Name: "cpu", Label: "cpu", Diff: false, Stacked: false},
			},
		},
		fmt.Sprintf("%s-windows-process-stats.memory.#", prefix): mp.Graphs{
			Label: fmt.Sprintf("%s Windows Process Stats Memory", prefix),
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "working_set", Label: "memory", Diff: false, Stacked: false},
			},
		},
	}
}

// Do the plugin
func Do() {
	optProcess := flag.String("process", "", "Process name")
	optMetricKeyPrefix := flag.String("metric-key-prefix", "", "Metric Key Prefix")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	if *optProcess == "" {
		logger.Warningf("Process name is required")
		flag.PrintDefaults()
		os.Exit(1)
	}

	var plugin WindowsProcessStatsPlugin
	plugin.Process = *optProcess
	metricLabel := *optMetricKeyPrefix
	if metricLabel == "" {
		metricLabel = plugin.Process
	}
	plugin.MetricLabel = metricLabel

	helper := mp.NewMackerelPlugin(plugin)
	helper.Tempfile = *optTempfile
	helper.Run()
}
<commit_msg>implement "PluginWithPrefix" interface<commit_after>// +build windows

package mpwindowsprocessstats

import (
	"flag"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strconv"

	"github.com/StackExchange/wmi"
	mp "github.com/mackerelio/go-mackerel-plugin-helper"
	"github.com/mackerelio/golib/logging"
)

var logger = logging.GetLogger("metrics.plugin.windows-process-stats")

type Win32_PerfFormattedData_PerfProc_Process struct {
	ElapsedTime          uint64
	Name                 string
	IDProcess            uint32
	PercentProcessorTime uint64
	WorkingSet           uint64
}

type WindowsProcessStatsPlugin struct {
	Process string
	Prefix  string
}

func getProcesses(processName string) ([]Win32_PerfFormattedData_PerfProc_Process, error) {
	var procs []Win32_PerfFormattedData_PerfProc_Process

	q := wmi.CreateQuery(&procs, "WHERE Name like '"+processName+"%'")
	if err := wmi.Query(q, &procs); err != nil {
		return procs, err
	}

	sort.Slice(procs, func(i, j int) bool {
		return procs[i].IDProcess < procs[j].IDProcess
	})
	return procs, nil
}

// FetchMetrics interface for mackerelplugin
func (m WindowsProcessStatsPlugin) FetchMetrics() (map[string]interface{}, error) {
	procs, err := getProcesses(m.Process)
	if err != nil {
		return nil, err
	}
	stat := make(map[string]interface{})
	prefix := m.MetricKeyPrefix()
	var re = regexp.MustCompile(`#[0-9]+$`)
	for k, v := range procs {
		name := re.ReplaceAllString(v.Name, "")
		processName := name + "_" + strconv.Itoa(k)
		metricNameCPU := prefix + "-windows-process-stats.cpu." + processName + ".cpu"
		metricNameMemory := prefix + "-windows-process-stats.memory." + processName + ".working_set"
		stat[metricNameCPU] = v.PercentProcessorTime
		stat[metricNameMemory] = v.WorkingSet
	}

	return stat, nil
}

// GraphDefinition interface for mackerelplugin
func (m WindowsProcessStatsPlugin) GraphDefinition() map[string](mp.Graphs) {
	prefix := m.MetricKeyPrefix()
	return map[string](mp.Graphs){
		fmt.Sprintf("%s-windows-process-stats.cpu.#", prefix): mp.Graphs{
			Label: fmt.Sprintf("%s Windows Process Stats CPU", prefix),
			Unit:  "percentage",
			Metrics: []mp.Metrics{
				{Name: "cpu", Label: "cpu", Diff: false, Stacked: false},
			},
		},
		fmt.Sprintf("%s-windows-process-stats.memory.#", prefix): mp.Graphs{
			Label: fmt.Sprintf("%s Windows Process Stats Memory", prefix),
			Unit:  "bytes",
			Metrics: []mp.Metrics{
				{Name: "working_set", Label: "memory", Diff: false, Stacked: false},
			},
		},
	}
}

// MetricKeyPrefix interface for mackerelplugin
func (m WindowsProcessStatsPlugin) MetricKeyPrefix() string {
	if m.Prefix == "" {
		return m.Process
	}
	return m.Prefix
}

// Do the plugin
func Do() {
	optProcess := flag.String("process", "", "Process name")
	optMetricKeyPrefix := flag.String("metric-key-prefix", "", "Metric Key Prefix")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	if *optProcess == "" {
		logger.Warningf("Process name is required")
		flag.PrintDefaults()
		os.Exit(1)
	}

	var plugin WindowsProcessStatsPlugin
	plugin.Process = *optProcess
	plugin.Prefix = *optMetricKeyPrefix

	helper := mp.NewMackerelPlugin(plugin)
	helper.Tempfile = *optTempfile
	helper.Run()
}
<|endoftext|>