<commit_before>package main

import (
	"crypto/md5"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"strings"

	"github.com/bwmarrin/discordgo"
	"golang.org/x/crypto/bcrypt"
)

func init() {
	newCommand("encode", 0, false, false, msgEncode).setHelp("Args: [base] [text]\n\nBases: `base64`, `bcrypt`, `md5`, `sh256`\nEncodes the given text in the given base.\n\nExample:\n`!owo encode md5 some text`").add()
}

func msgEncode(s *discordgo.Session, m *discordgo.MessageCreate, msglist []string) {
	if len(msglist) < 3 {
		return
	}

	base := strings.ToLower(msglist[1])
	text := strings.Join(msglist[2:], " ")
	var output []byte

	s.ChannelTyping(m.ChannelID)

	switch base {
	case "base64":
		base64.StdEncoding.Encode(output, []byte(text))
	case "bcrypt":
		var err error
		if output, err = bcrypt.GenerateFromPassword([]byte(text), 14); err != nil {
			log.Error("bcrypt err", err)
			return
		}
	case "md5":
		hash := md5.Sum([]byte(text))
		hex.Encode(output, hash[:])
	case "sha256":
		hash := sha256.Sum256([]byte(text))
		hex.Encode(output, hash[:])
	}

	if len(output) == 0 {
		s.ChannelMessageSend(m.ChannelID, "Base not supported")
		return
	}

	s.ChannelMessageSend(m.ChannelID, string(output))
}
<commit_msg>Fixed out of range in hashing<commit_after>package main

import (
	"crypto/md5"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"strings"

	"github.com/bwmarrin/discordgo"
	"golang.org/x/crypto/bcrypt"
)

func init() {
	newCommand("encode", 0, false, false, msgEncode).setHelp("Args: [base] [text]\n\nBases: `base64`, `bcrypt`, `md5`, `sh256`\nEncodes the given text in the given base.\n\nExample:\n`!owo encode md5 some text`").add()
}

func msgEncode(s *discordgo.Session, m *discordgo.MessageCreate, msglist []string) {
	if len(msglist) < 3 {
		return
	}

	base := strings.ToLower(msglist[1])
	text := strings.Join(msglist[2:], " ")
	var output []byte

	s.ChannelTyping(m.ChannelID)

	switch base {
	case "base64":
		base64.StdEncoding.Encode(output, []byte(text))
	case "bcrypt":
		var err error
		if output, err = bcrypt.GenerateFromPassword([]byte(text), 14); err != nil {
			log.Error("bcrypt err", err)
			return
		}
	case "md5":
		hash := md5.Sum([]byte(text))
		output = make([]byte, hex.EncodedLen(len(hash)))
		hex.Encode(output, hash[:])
	case "sha256":
		hash := sha256.Sum256([]byte(text))
		output = make([]byte, hex.EncodedLen(len(hash)))
		hex.Encode(output, hash[:])
	default:
		s.ChannelMessageSend(m.ChannelID, "Base not supported")
		return
	}

	s.ChannelMessageSend(m.ChannelID, string(output))
}
<|endoftext|>


<commit_before>package acl

import (
	"reflect"
	"testing"
)

func TestParse(t *testing.T) {
	inp := `
key "" {
	policy = "read"
}
key "foo/" {
	policy = "write"
}
key "foo/bar/" {
	policy = "read"
}
key "foo/bar/baz" {
	policy = "deny"
}
	`
	exp := &Policy{
		Keys: []*KeyPolicy{
			&KeyPolicy{
				Prefix: "",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/",
				Policy: KeyPolicyWrite,
			},
			&KeyPolicy{
				Prefix: "foo/bar/",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/bar/baz",
				Policy: KeyPolicyDeny,
			},
		},
	}

	out, err := Parse(inp)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if !reflect.DeepEqual(out, exp) {
		t.Fatalf("bad: %#v %#v", out, exp)
	}
}
<commit_msg>acl: Test parsing JSON<commit_after>package acl

import (
	"reflect"
	"testing"
)

func TestParse(t *testing.T) {
	inp := `
key "" {
	policy = "read"
}
key "foo/" {
	policy = "write"
}
key "foo/bar/" {
	policy = "read"
}
key "foo/bar/baz" {
	policy = "deny"
}
	`
	exp := &Policy{
		Keys: []*KeyPolicy{
			&KeyPolicy{
				Prefix: "",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/",
				Policy: KeyPolicyWrite,
			},
			&KeyPolicy{
				Prefix: "foo/bar/",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/bar/baz",
				Policy: KeyPolicyDeny,
			},
		},
	}

	out, err := Parse(inp)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if !reflect.DeepEqual(out, exp) {
		t.Fatalf("bad: %#v %#v", out, exp)
	}
}

func TestParse_JSON(t *testing.T) {
	inp := `{
	"key": {
		"": {
			"policy": "read"
		},
		"foo/": {
			"policy": "write"
		},
		"foo/bar/": {
			"policy": "read"
		},
		"foo/bar/baz": {
			"policy": "deny"
		}
	}
}`
	exp := &Policy{
		Keys: []*KeyPolicy{
			&KeyPolicy{
				Prefix: "",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/",
				Policy: KeyPolicyWrite,
			},
			&KeyPolicy{
				Prefix: "foo/bar/",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/bar/baz",
				Policy: KeyPolicyDeny,
			},
		},
	}

	out, err := Parse(inp)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if !reflect.DeepEqual(out, exp) {
		t.Fatalf("bad: %#v %#v", out, exp)
	}
}
<|endoftext|>


<commit_before>package actions

import (
	"log"
	"net/http"
	"github.com/julienschmidt/httprouter"
	"image"
)

import _ "image/jpeg"

/* Constants */
var MaxFileSize = int64(1024 * 1024 * 5) // MB
var TileSize = 64 // pixels

/* Let's use here the CRUD standard names */
func Create(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {

    log.Printf("Received new slapchop!")
    r.ParseMultipartForm(MaxFileSize)

    // Opening the file
    file, _, err := r.FormFile("uploadfile")
    if err != nil {
    	log.Println(err)
        return
    }
    defer file.Close() // Setting to close filehandler at the end of this function

    // Decoding the image from the file
    img, format, err := image.Decode(file)
    if err != nil {
    	log.Println(err)
        return
    }

	// Getting img dimensions, that we can decide how to slice it
    bounds := img.Bounds()
    log.Println(bounds.Min.X, bounds.Max.X, bounds.Min.X, bounds.Max.Y)

    n_x := bounds.Max.X/TileSize // Number of tiles in the X axis
    n_y := bounds.Max.Y/TileSize // Number of tiles in the Y axis
    log.Println("N. Tiles: ",  n_x, n_y)
    log.Println("Succesfully loaded image!", &img, format)

}

func Read(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    log.Printf("Requesting slapchop")
    chop_id := ps.ByName("chopid")
    log.Println(chop_id)
}
<commit_msg>cutting system in place<commit_after>package actions

import (
	"os"
	"log"
	"fmt"
	"net/http"
	"image"
	"image/jpeg"
	"image/draw"
	"github.com/julienschmidt/httprouter"
)

/* Constants */
var MaxFileSize = int64(1024 * 1024 * 5) // MB
var TileSize = 64 // pixels

/* Let's use here the CRUD standard names */
func Create(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {

    log.Printf("Received new slapchop!")
    r.ParseMultipartForm(MaxFileSize)

    // Opening the file
    file, _, err := r.FormFile("uploadfile")
    if err != nil {
    	log.Println(err)
        return
    }
    defer file.Close() // Setting to close filehandler at the end of this function

    // Decoding the image from the file
    img, format, err := image.Decode(file)
    if err != nil {
    	log.Println(err)
        return
    }

	// Getting img dimensions, that we can decide how to slice it
    bounds := img.Bounds()

    n_x := bounds.Max.X/TileSize // Number of tiles in the X axis
    n_y := bounds.Max.Y/TileSize // Number of tiles in the Y axis
    log.Println("N. Tiles: ",  n_x, n_y)
    log.Println("Succesfully loaded image!", &img, format)

    // Drawing the multiple rectangles
    for x := 0; x < n_x; x++ {
    	for y := 0; y < n_y; y++ {
    		rxi := x * TileSize
    		ryi := y * TileSize
    		rxj := rxi + TileSize
			ryj := ryi + TileSize

    		cropR := image.Rect(rxi, ryi, rxj, ryj)
    		cropR = img.Bounds().Intersect(cropR)
    		log.Println(cropR.Min.X, cropR.Min.Y, cropR.Max.X, cropR.Max.Y)

    		subImg := image.NewRGBA(image.Rect(0, 0, TileSize, TileSize))
    		draw.Draw(subImg, subImg.Bounds(), img, cropR.Min, draw.Src)

    		tile_file_name := fmt.Sprintf("upload/%d_%d.jpg", y, x)
    		toimg, _ := os.Create(tile_file_name)
    		defer toimg.Close()

    		jpeg.Encode(toimg, subImg, &jpeg.Options{jpeg.DefaultQuality})
		}
    }

}

func Read(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    log.Printf("Requesting slapchop")
    chop_id := ps.ByName("chopid")
    log.Println(chop_id)
}
<|endoftext|>


<commit_before>package multipass

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"crypto/sha1"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"

	"code.google.com/p/go.crypto/pbkdf2"
)

func clear(b []byte) {
	for i := 0; i < len(b); i++ {
		b[i] = 0
	}
}

type KeyChain interface {
	Open(password []byte) error
	IsOpen() bool
	Close()
	ForEachItem(callback ItemCallback) error
	Keys() map[string][]byte
}

type AgileKeyChain struct {
	dir  string
	keys map[string][]byte
}

func NewAgileKeyChain(dir string) KeyChain {
	// TODO check it is a 1Password dir
	return &AgileKeyChain{dir: dir}
}

func (chain *AgileKeyChain) Close() {
	chain.keys = nil
}

func (chain *AgileKeyChain) IsOpen() bool {
	return chain.keys != nil
}

func (chain *AgileKeyChain) Keys() map[string][]byte {
	return chain.keys
}

func (chain *AgileKeyChain) ForEachItem(callback ItemCallback) error {
	return ForEachItem(chain.dir, callback)
}

func (chain *AgileKeyChain) Open(password []byte) error {
	file, err := ioutil.ReadFile(path.Join(chain.dir, "encryptionKeys.js"))
	if err != nil {
		return err
	}

	var keys Keys
	err = json.Unmarshal(file, &keys)
	if err != nil {
		return err
	}

	//fmt.Printf("%+v\n", keys)

	keyMap := make(map[string][]byte)
	for _, passKey := range keys.List {
		err = DecryptKey(password, passKey, keyMap)
		if err != nil {
			return err
		}
	}

	chain.keys = keyMap

	return nil
}

type ItemCallback func(path string, file []byte) error

func ForEachItem(onePasswordDir string, itemCallback ItemCallback) error {
	dirListing, e := ioutil.ReadDir(onePasswordDir)
	if e != nil {
		return e
	}
	for _, f := range dirListing {
		if !f.IsDir() && path.Ext(f.Name()) == ".1password" {
			p := path.Join(onePasswordDir, f.Name())
			file, err := ioutil.ReadFile(p)
			if err != nil {
				return err
			}
			err = itemCallback(p, file)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

type PassKey struct {
	// Base64 encoded encryption key, AES-128 encrypted using a PBKDF2 key
	// derived from the user's password
	Data       string
	Identifier string
	Iterations int
	Level      string
	// Base64 encoded copy of the encryption key, AES-128 encrypted by itself
	Validation string
}

type Keys struct {
	List []PassKey
}

var saltMarker []byte = []byte("Salted__")
var saltLen int = len(saltMarker)

const saltDataLen = 8

func IsSalted(encryptedData []byte) bool {
	if len(encryptedData) < saltLen {
		return false
	}

	return bytes.Equal(encryptedData[:saltLen], saltMarker)
}

func DecryptKey(pass []byte, passKey PassKey, keyMap map[string][]byte) error {
	encryptedEncryptionKey, er := Base64Decode(passKey.Data)

	if er != nil {
		fmt.Println(er)
		os.Exit(1)
	}

	var salt []byte
	if IsSalted(encryptedEncryptionKey) {
		// salt marker (8 bytes) | salt (8 bytes) | data
		skip := saltLen + saltDataLen
		salt = []byte(encryptedEncryptionKey[saltLen:skip])
		encryptedEncryptionKey = encryptedEncryptionKey[skip:]
	}

	// first 16 bytes are the key, last 16 bytes are the IV
	bytez := pbkdf2.Key(pass, salt, passKey.Iterations, aes.BlockSize*2, sha1.New)
	key := bytez[:16] // aes key size must be 16, 24 or 32
	iv := bytez[16:]  // IV byte length is equal to aes.BlockSize

	// 16 byte key, so AES-128
	b, e := DecryptAes(key, iv, encryptedEncryptionKey)
	if e != nil {
		fmt.Println("decrypt error")
		os.Exit(1)
	}

	validationData := passKey.Validation
	validation, er := base64.StdEncoding.DecodeString(validationData[0 : len(validationData)-1])
	v, _ := DecryptData(b, validation)

	if !bytes.Equal(b, v) {
		return errors.New("encryption key validation failed")
	}

	keyMap[passKey.Level] = b

	return nil
}

type Item struct {
	Title    string
	Payload  string
	TypeName string
}

func DecryptFile(file []byte, keyMap map[string][]byte) (Item, error) {
	type EncryptedItem struct {
		Title     string
		Encrypted string

		// determine which encryption key to use; values are SL3 or SL5 in my keychain
		// currently we assume SL5 if this field is empty
		// TODO add openContents.securityLevel field, it seems to be an altenative
		SecurityLevel string

		// Known values (there are probably others):
		//   passwords.Password
		//   webforms.WebForm
		//   system.folder.SavedSearch
		//   securenotes.SecureNote
		//   wallet.financial.CreditCard
		//   wallet.computer.License
		//   identities.Identity
		TypeName string
	}

	var item EncryptedItem
	err := json.Unmarshal(file, &item)
	if err != nil {
		return Item{}, err
	}

	//fmt.Printf("%+v\n", item)

	decoded, er := Base64Decode(item.Encrypted)

	if er != nil {
		return Item{}, er
	}

	securityLevel := item.SecurityLevel
	if len(securityLevel) == 0 {
		securityLevel = "SL5"
	}

	decrypted, e := DecryptData(keyMap[securityLevel], decoded)

	if e != nil {
		return Item{}, e
	}

	return Item{Title: item.Title, Payload: string(decrypted), TypeName: item.TypeName}, nil
}

func Base64Decode(data string) ([]byte, error) {
	actualData := data
	if data[len(data)-1] == 0 {
		actualData = data[:len(data)-1]
	}

	decoded, err := base64.StdEncoding.DecodeString(actualData)

	if err != nil {
		return nil, err
	}

	return decoded, nil
}

func DecryptData(key, data []byte) ([]byte, error) {
	if !IsSalted(data) {
		return nil, errors.New("unsalted data not supported")
	}

	// assuming salt
	salt := data[saltLen : saltLen+saltDataLen]
	data = data[saltLen+saltDataLen:]

	// poor man's MD5 based PBKDF1
	nkey := md5.Sum(append(key, salt...))
	iv := md5.Sum(append(append(nkey[:], key...), salt...))

	// 16 byte key, so AES-128
	result, err := DecryptAes(nkey[:], iv[:], data)

	if err != nil {
		fmt.Println("decryption error")
		return nil, err
	}

	return result, nil
}

// https://leanpub.com/gocrypto/read#leanpub-auto-encrypting-and-decrypting-data-with-aes-cbc
// https://github.com/kisom/gocrypto/blob/master/chapter2/aescbc/aescbc.go
// Decrypt decrypts the message and removes any padding.
func DecryptAes(k, iv, in []byte) ([]byte, error) {
	if len(in) == 0 || len(in)%aes.BlockSize != 0 {
		return nil, errors.New("input block size not a multiple of aes.BlockSize")
	}

	c, err := aes.NewCipher(k)
	if err != nil {
		// potentially wrong key size, must be one of 16/24/32
		// to select AES-128, AES-192 or AES-256 respectively
		return nil, err
	}

	// iv must be == aes.BlockSize
	cbc := cipher.NewCBCDecrypter(c, iv)
	cbc.CryptBlocks(in, in)

	out := Unpad(in)
	if out == nil {
		return nil, errors.New("failed to remove padding")
	}

	return out, nil
}

// Pad applies the PKCS #7 padding scheme on the buffer.
func Pad(in []byte) []byte {
	padding := 16 - (len(in) % 16)
	if padding == 0 {
		padding = 16
	}
	for i := 0; i < padding; i++ {
		in = append(in, byte(padding))
	}
	return in
}

// Unpad strips the PKCS #7 padding on a buffer. If the padding is
// invalid, nil is returned.
func Unpad(in []byte) []byte {
	if len(in) == 0 {
		return nil
	}

	padding := in[len(in)-1]
	if int(padding) > len(in) || padding > aes.BlockSize {
		return nil
	} else if padding == 0 {
		return nil
	}

	for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
		if in[i] != padding {
			return nil
		}
	}
	return in[:len(in)-int(padding)]
}
<commit_msg>no longer write to stdout<commit_after>package multipass

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"crypto/sha1"
	"encoding/base64"
	"encoding/json"
	"errors"
	"io/ioutil"
	"os"
	"path"

	"code.google.com/p/go.crypto/pbkdf2"
)

func clear(b []byte) {
	for i := 0; i < len(b); i++ {
		b[i] = 0
	}
}

type KeyChain interface {
	Open(password []byte) error
	IsOpen() bool
	Close()
	ForEachItem(callback ItemCallback) error
	Keys() map[string][]byte
}

type AgileKeyChain struct {
	dir  string
	keys map[string][]byte
}

func NewAgileKeyChain(dir string) KeyChain {
	// TODO check it is a 1Password dir
	return &AgileKeyChain{dir: dir}
}

func (chain *AgileKeyChain) Close() {
	chain.keys = nil
}

func (chain *AgileKeyChain) IsOpen() bool {
	return chain.keys != nil
}

func (chain *AgileKeyChain) Keys() map[string][]byte {
	return chain.keys
}

func (chain *AgileKeyChain) ForEachItem(callback ItemCallback) error {
	return ForEachItem(chain.dir, callback)
}

func (chain *AgileKeyChain) Open(password []byte) error {
	file, err := ioutil.ReadFile(path.Join(chain.dir, "encryptionKeys.js"))
	if err != nil {
		return err
	}

	var keys Keys
	err = json.Unmarshal(file, &keys)
	if err != nil {
		return err
	}

	//fmt.Printf("%+v\n", keys)

	keyMap := make(map[string][]byte)
	for _, passKey := range keys.List {
		err = DecryptKey(password, passKey, keyMap)
		if err != nil {
			return err
		}
	}

	chain.keys = keyMap

	return nil
}

type ItemCallback func(path string, file []byte) error

func ForEachItem(onePasswordDir string, itemCallback ItemCallback) error {
	dirListing, e := ioutil.ReadDir(onePasswordDir)
	if e != nil {
		return e
	}
	for _, f := range dirListing {
		if !f.IsDir() && path.Ext(f.Name()) == ".1password" {
			p := path.Join(onePasswordDir, f.Name())
			file, err := ioutil.ReadFile(p)
			if err != nil {
				return err
			}
			err = itemCallback(p, file)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

type PassKey struct {
	// Base64 encoded encryption key, AES-128 encrypted using a PBKDF2 key
	// derived from the user's password
	Data       string
	Identifier string
	Iterations int
	Level      string
	// Base64 encoded copy of the encryption key, AES-128 encrypted by itself
	Validation string
}

type Keys struct {
	List []PassKey
}

var saltMarker []byte = []byte("Salted__")
var saltLen int = len(saltMarker)

const saltDataLen = 8

func IsSalted(encryptedData []byte) bool {
	if len(encryptedData) < saltLen {
		return false
	}

	return bytes.Equal(encryptedData[:saltLen], saltMarker)
}

func DecryptKey(pass []byte, passKey PassKey, keyMap map[string][]byte) error {
	encryptedEncryptionKey, er := Base64Decode(passKey.Data)

	if er != nil {
		return er
	}

	var salt []byte
	if IsSalted(encryptedEncryptionKey) {
		// salt marker (8 bytes) | salt (8 bytes) | data
		skip := saltLen + saltDataLen
		salt = []byte(encryptedEncryptionKey[saltLen:skip])
		encryptedEncryptionKey = encryptedEncryptionKey[skip:]
	}

	// first 16 bytes are the key, last 16 bytes are the IV
	bytez := pbkdf2.Key(pass, salt, passKey.Iterations, aes.BlockSize*2, sha1.New)
	key := bytez[:16] // aes key size must be 16, 24 or 32
	iv := bytez[16:]  // IV byte length is equal to aes.BlockSize

	// 16 byte key, so AES-128
	b, e := DecryptAes(key, iv, encryptedEncryptionKey)
	if e != nil {
		return e
	}

	validationData := passKey.Validation
	validation, er := base64.StdEncoding.DecodeString(validationData[0 : len(validationData)-1])
	v, _ := DecryptData(b, validation)

	if !bytes.Equal(b, v) {
		return errors.New("encryption key validation failed")
	}

	keyMap[passKey.Level] = b

	return nil
}

type Item struct {
	Title    string
	Payload  string
	TypeName string
}

func DecryptFile(file []byte, keyMap map[string][]byte) (Item, error) {
	type EncryptedItem struct {
		Title     string
		Encrypted string

		// determine which encryption key to use; values are SL3 or SL5 in my keychain
		// currently we assume SL5 if this field is empty
		// TODO add openContents.securityLevel field, it seems to be an altenative
		SecurityLevel string

		// Known values (there are probably others):
		//   passwords.Password
		//   webforms.WebForm
		//   system.folder.SavedSearch
		//   securenotes.SecureNote
		//   wallet.financial.CreditCard
		//   wallet.computer.License
		//   identities.Identity
		TypeName string
	}

	var item EncryptedItem
	err := json.Unmarshal(file, &item)
	if err != nil {
		return Item{}, err
	}

	//fmt.Printf("%+v\n", item)

	decoded, er := Base64Decode(item.Encrypted)

	if er != nil {
		return Item{}, er
	}

	securityLevel := item.SecurityLevel
	if len(securityLevel) == 0 {
		securityLevel = "SL5"
	}

	decrypted, e := DecryptData(keyMap[securityLevel], decoded)

	if e != nil {
		return Item{}, e
	}

	return Item{Title: item.Title, Payload: string(decrypted), TypeName: item.TypeName}, nil
}

func Base64Decode(data string) ([]byte, error) {
	actualData := data
	if data[len(data)-1] == 0 {
		actualData = data[:len(data)-1]
	}

	decoded, err := base64.StdEncoding.DecodeString(actualData)

	if err != nil {
		return nil, err
	}

	return decoded, nil
}

func DecryptData(key, data []byte) ([]byte, error) {
	if !IsSalted(data) {
		return nil, errors.New("unsalted data not supported")
	}

	// assuming salt
	salt := data[saltLen : saltLen+saltDataLen]
	data = data[saltLen+saltDataLen:]

	// poor man's MD5 based PBKDF1
	nkey := md5.Sum(append(key, salt...))
	iv := md5.Sum(append(append(nkey[:], key...), salt...))

	// 16 byte key, so AES-128
	result, err := DecryptAes(nkey[:], iv[:], data)

	if err != nil {
		return nil, err
	}

	return result, nil
}

// https://leanpub.com/gocrypto/read#leanpub-auto-encrypting-and-decrypting-data-with-aes-cbc
// https://github.com/kisom/gocrypto/blob/master/chapter2/aescbc/aescbc.go
// Decrypt decrypts the message and removes any padding.
func DecryptAes(k, iv, in []byte) ([]byte, error) {
	if len(in) == 0 || len(in)%aes.BlockSize != 0 {
		return nil, errors.New("input block size not a multiple of aes.BlockSize")
	}

	c, err := aes.NewCipher(k)
	if err != nil {
		// potentially wrong key size, must be one of 16/24/32
		// to select AES-128, AES-192 or AES-256 respectively
		return nil, err
	}

	// iv must be == aes.BlockSize
	cbc := cipher.NewCBCDecrypter(c, iv)
	cbc.CryptBlocks(in, in)

	out := Unpad(in)
	if out == nil {
		return nil, errors.New("failed to remove padding")
	}

	return out, nil
}

// Pad applies the PKCS #7 padding scheme on the buffer.
func Pad(in []byte) []byte {
	padding := 16 - (len(in) % 16)
	if padding == 0 {
		padding = 16
	}
	for i := 0; i < padding; i++ {
		in = append(in, byte(padding))
	}
	return in
}

// Unpad strips the PKCS #7 padding on a buffer. If the padding is
// invalid, nil is returned.
func Unpad(in []byte) []byte {
	if len(in) == 0 {
		return nil
	}

	padding := in[len(in)-1]
	if int(padding) > len(in) || padding > aes.BlockSize {
		return nil
	} else if padding == 0 {
		return nil
	}

	for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
		if in[i] != padding {
			return nil
		}
	}
	return in[:len(in)-int(padding)]
}
<|endoftext|>


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

// The lint binary ensures the source tree is correctly formatted.
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/bazelbuild/rules_go/go/tools/bazel"
)

// getWorkspaceDir finds the path to the workspace given a path to a WORKSPACE file (which could be
// a symlink as staged by Bazel).  The returned path is absolute.
func getWorkspaceDir(file string) (string, error) {
	fileInfo, err := os.Lstat(file)
	if err != nil {
		return "", fmt.Errorf("cannot find %s: %v", file, err)
	}

	var dir string
	if fileInfo.Mode()&os.ModeType == os.ModeSymlink {
		realFile, err := os.Readlink(file)
		if err != nil {
			return "", fmt.Errorf("cannot read link %s: %v", file, err)
		}
		dir = filepath.Dir(realFile)
	} else {
		dir = filepath.Dir(file)
	}

	dir, err = filepath.Abs(dir)
	if err != nil {
		return "", fmt.Errorf("cannot convert %s to an absolute path: %v", dir, err)
	}

	// We have computed the real path to the workspace.  Now... let's make sure that's true by
	// looking for a known file.
	fileInfo, err = os.Stat(filepath.Join(dir, "README.md"))
	if err != nil {
		return "", fmt.Errorf("cannot find README.md in workspace %s: %v", dir, err)
	}
	if fileInfo.Mode()&os.ModeType != 0 {
		return "", fmt.Errorf("workspace %s contents are not regular files", dir)
	}

	return dir, nil
}

// isBlacklisted returns true if the given filename should not be linted.  The workspaceDir
// directory must be absolute as returned by getWorkspaceDir() and the candidate must have that
// path as a prefix.
func isBlacklisted(workspaceDir string, candidate string) (bool, error) {
	relative, err := filepath.Rel(workspaceDir, candidate)
	if err != nil {
		return false, fmt.Errorf("%s is not within the workspace %s", candidate, workspaceDir)
	}

	// Skip hidden files as we don't need to run checks on them.  (This is not strictly
	// true, but it's simpler this way for now and the risk is low given that the hidden
	// files we have are trivial.)
	if strings.HasPrefix(relative, ".") {
		return true, nil
	}

	// Skip the Rust build directory.
	if strings.HasPrefix(candidate, "target/") {
		return true, nil
	}

	return false, nil
}

// collectFiles scans the given directory recursively and returns the paths to all regular files
// within it.
func collectFiles(dir string) ([]string, error) {
	files := make([]string, 0)

	collector := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if blacklisted, err := isBlacklisted(dir, path); blacklisted || err != nil {
			return err
		}

		if info.Mode()&os.ModeType == 0 {
			files = append(files, path)
		}

		return err
	}

	return files, filepath.Walk(dir, collector)
}

func main() {
	verbose := flag.Bool("verbose", false, "Enables extra logging")
	workspace := flag.String("workspace", "WORKSPACE", "Path to the WORKSPACE file where the source tree list; used to find source files (symlinks are followed) and to resolve relative paths to sources")
	flag.Parse()

	if *verbose {
		log.SetOutput(os.Stderr)
	} else {
		log.SetOutput(ioutil.Discard)
	}

	if err := bazel.EnterRunfiles("sandboxfs", "admin/lint", "lint", "admin/lint"); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
		os.Exit(1)
	}

	workspaceDir, err := getWorkspaceDir(*workspace)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
		os.Exit(1)
	}

	var files []string
	if len(flag.Args()) == 0 {
		log.Printf("Searching for source files in %s", workspaceDir)
		allFiles, err := collectFiles(workspaceDir)
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
			os.Exit(1)
		}
		files = allFiles
	} else {
		files = make([]string, 0, len(flag.Args()))
		for _, file := range flag.Args() {
			if filepath.IsAbs(file) {
				fmt.Fprintf(os.Stderr, "ERROR: Explicitly-provided file names must be relative; %s was not\n", file)
				os.Exit(1)
			}
			candidate := filepath.Join(workspaceDir, file)
			blacklisted, err := isBlacklisted(workspaceDir, candidate)
			if err != nil {
				fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
				os.Exit(1)
			}
			if blacklisted {
				log.Printf("Skipping linting of explicitly-specified %s because it is blacklisted", file)
			} else {
				files = append(files, candidate)
			}
		}
	}

	failed := false
	for _, file := range files {
		if !checkAll(file) {
			failed = true
		}
	}
	if failed {
		os.Exit(1)
	}
}
<commit_msg>Homogenize application of blacklist to input files<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License.  You may obtain a copy
// of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
// License for the specific language governing permissions and limitations
// under the License.

// The lint binary ensures the source tree is correctly formatted.
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/bazelbuild/rules_go/go/tools/bazel"
)

// getWorkspaceDir finds the path to the workspace given a path to a WORKSPACE file (which could be
// a symlink as staged by Bazel).  The returned path is absolute.
func getWorkspaceDir(file string) (string, error) {
	fileInfo, err := os.Lstat(file)
	if err != nil {
		return "", fmt.Errorf("cannot find %s: %v", file, err)
	}

	var dir string
	if fileInfo.Mode()&os.ModeType == os.ModeSymlink {
		realFile, err := os.Readlink(file)
		if err != nil {
			return "", fmt.Errorf("cannot read link %s: %v", file, err)
		}
		dir = filepath.Dir(realFile)
	} else {
		dir = filepath.Dir(file)
	}

	dir, err = filepath.Abs(dir)
	if err != nil {
		return "", fmt.Errorf("cannot convert %s to an absolute path: %v", dir, err)
	}

	// We have computed the real path to the workspace.  Now... let's make sure that's true by
	// looking for a known file.
	fileInfo, err = os.Stat(filepath.Join(dir, "README.md"))
	if err != nil {
		return "", fmt.Errorf("cannot find README.md in workspace %s: %v", dir, err)
	}
	if fileInfo.Mode()&os.ModeType != 0 {
		return "", fmt.Errorf("workspace %s contents are not regular files", dir)
	}

	return dir, nil
}

// isBlacklisted returns true if the given filename should not be linted.  The candidate must be
// given as a relative path to the workspace directory.
func isBlacklisted(candidate string) bool {
	// Skip hidden files as we don't need to run checks on them.  (This is not strictly
	// true, but it's simpler this way for now and the risk is low given that the hidden
	// files we have are trivial.)
	if strings.HasPrefix(candidate, ".") {
		return true
	}

	// Skip the Rust build directory.
	if strings.HasPrefix(candidate, "target/") {
		return true
	}

	return false
}

// collectFiles scans the given directory recursively and returns the paths to all regular files
// within it as relative paths to the given directory.
func collectFiles(dir string) ([]string, error) {
	files := make([]string, 0)

	collector := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		relative, err := filepath.Rel(dir, path)
		if err != nil {
			panic(fmt.Sprintf("%s is not within %s but it should have been", path, dir))
		}
		if info.Mode()&os.ModeType == 0 {
			files = append(files, relative)
		}

		return err
	}

	return files, filepath.Walk(dir, collector)
}

func main() {
	verbose := flag.Bool("verbose", false, "Enables extra logging")
	workspace := flag.String("workspace", "WORKSPACE", "Path to the WORKSPACE file where the source tree list; used to find source files (symlinks are followed) and to resolve relative paths to sources")
	flag.Parse()

	if *verbose {
		log.SetOutput(os.Stderr)
	} else {
		log.SetOutput(ioutil.Discard)
	}

	if err := bazel.EnterRunfiles("sandboxfs", "admin/lint", "lint", "admin/lint"); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
		os.Exit(1)
	}

	workspaceDir, err := getWorkspaceDir(*workspace)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
		os.Exit(1)
	}

	var relFiles []string
	if len(flag.Args()) == 0 {
		log.Printf("Searching for source files in %s", workspaceDir)
		relFiles, err = collectFiles(workspaceDir)
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
			os.Exit(1)
		}
	} else {
		for _, file := range flag.Args() {
			if filepath.IsAbs(file) {
				fmt.Fprintf(os.Stderr, "ERROR: Explicitly-provided file names must be relative; %s was not\n", file)
				os.Exit(1)
			}
		}
		relFiles = flag.Args()
	}

	files := make([]string, 0, len(relFiles))
	for _, file := range relFiles {
		if isBlacklisted(file) {
			log.Printf("Skipping linting of %s because it is blacklisted", file)
		} else {
			files = append(files, filepath.Join(workspaceDir, file))
		}
	}

	failed := false
	for _, file := range files {
		if !checkAll(file) {
			failed = true
		}
	}
	if failed {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Nicolas Lamirault <nicolas.lamirault@gmail.com>

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

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package command

import (
	"flag"
	"fmt"
	"strings"

	"github.com/mitchellh/cli"
	"github.com/mitchellh/colorstring"

	"github.com/nlamirault/guzuta/logging"
	"github.com/nlamirault/guzuta/providers/travisci"
	"github.com/nlamirault/guzuta/utils"
)

// TravisCICommand represents CLI command for TravisCI provider
type TravisCICommand struct {
	UI cli.Ui
}

func (c *TravisCICommand) Help() string {
	helpText := `
Usage: guzuta travisci [options]
	Check projects status from TravisCI
Options:
	--debug                       Debug mode enabled
	--travis-name=name            Project name
	--travis-namespace=namespace  Namespace
`
	return strings.TrimSpace(helpText)
}

func (c *TravisCICommand) Synopsis() string {
	return "Check projects status from TravisCI"
}

func (c *TravisCICommand) Run(args []string) int {
	var debug bool
	var name, namespace string
	f := flag.NewFlagSet("travis", flag.ContinueOnError)
	f.Usage = func() { c.UI.Output(c.Help()) }
	f.BoolVar(&debug, "debug", false, "Debug mode enabled")
	f.StringVar(&name, "travis-name", "", "TravisCI project's name")
	f.StringVar(&namespace, "travis-namespace", "", "TravisCI namespace")

	if err := f.Parse(args); err != nil {
		return 1
	}
	if debug {
		c.UI.Info("Debug mode enabled.")
		logging.SetLogging("DEBUG")
	} else {
		logging.SetLogging("INFO")
	}
	client := travisci.NewClient(utils.Getenv("GUZUTA_TRAVIS_GITHUB_TOKEN"))
	if len(name) > 0 {
		travisRepositoryStatus(client, name)
		return 0
	}
	if len(namespace) > 0 {
		travisRepositoriesStatus(client, namespace)
		return 0
	}
	return 0
}

func travisRepositoryStatus(client *travisci.Client, name string) {
	resp, err := client.GetRepository(name)
	if err != nil {
		colorstring.Printf("[red] Travis : %s", err.Error())
		return
	}
	status := "[green] OK"
	if resp.Repository.LastBuildState == "failed" {
		status = "[red] KO"
	}
	fmt.Printf(colorstring.Color(status) + "\t" + resp.Repository.Slug + "\n")
}

func travisRepositoriesStatus(client *travisci.Client, namespace string) {
	resp, err := client.GetRepositories(namespace)
	if err != nil {
		colorstring.Printf("[red] Travis : %s", err.Error())
		return
	}
	for _, repo := range resp.Repositories {
		status := "[green] OK"
		if repo.LastBuildState == "failed" {
			status = "[red] KO"
		}
		fmt.Printf(colorstring.Color(status) + "\t" + repo.Slug + "\n")
	}
}
<commit_msg>Refactoring CLI for TravisCI<commit_after>// Copyright (C) 2015 Nicolas Lamirault <nicolas.lamirault@gmail.com>

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

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package command

import (
	"flag"
	"fmt"
	"strings"

	"github.com/mitchellh/cli"
	"github.com/mitchellh/colorstring"

	"github.com/nlamirault/guzuta/logging"
	"github.com/nlamirault/guzuta/providers/travisci"
	"github.com/nlamirault/guzuta/utils"
)

// TravisCICommand represents CLI command for TravisCI provider
type TravisCICommand struct {
	UI cli.Ui
}

func (c *TravisCICommand) Help() string {
	helpText := `
Usage: guzuta travisci [options]
	Check projects status from TravisCI
Options:
	--debug                   Debug mode enabled
	--name=name               Project name
	--namespace=namespace     Namespace
`
	return strings.TrimSpace(helpText)
}

func (c *TravisCICommand) Synopsis() string {
	return "Check projects status from TravisCI"
}

func (c *TravisCICommand) Run(args []string) int {
	var debug bool
	var name, namespace string
	f := flag.NewFlagSet("travis", flag.ContinueOnError)
	f.Usage = func() { c.UI.Output(c.Help()) }
	f.BoolVar(&debug, "debug", false, "Debug mode enabled")
	f.StringVar(&name, "name", "", "TravisCI project's name")
	f.StringVar(&namespace, "namespace", "", "TravisCI namespace")

	if err := f.Parse(args); err != nil {
		return 1
	}
	if debug {
		c.UI.Info("Debug mode enabled.")
		logging.SetLogging("DEBUG")
	} else {
		logging.SetLogging("INFO")
	}
	client := travisci.NewClient(utils.Getenv("GUZUTA_TRAVIS_GITHUB_TOKEN"))
	if len(name) > 0 && len(namespace) > 0 {
		travisRepositoryStatus(client, namespace, name)
		return 0
	}
	if len(namespace) > 0 {
		travisRepositoriesStatus(client, namespace)
		return 0
	}
	return 0
}

func travisRepositoryStatus(client *travisci.Client, namespace string, name string) {
	resp, err := client.GetRepository(fmt.Sprintf("%s/%s", namespace, name))
	if err != nil {
		colorstring.Printf("[red] Travis : %s", err.Error())
		return
	}
	travisPrintRepository(&resp.Repository)
}

func travisRepositoriesStatus(client *travisci.Client, namespace string) {
	resp, err := client.GetRepositories(namespace)
	if err != nil {
		colorstring.Printf("[red] Travis : %s", err.Error())
		return
	}
	for _, repo := range resp.Repositories {
		travisPrintRepository(&repo)
	}
}

func travisPrintRepository(repo *travisci.Repository) {
	status := ""
	if repo.LastBuildState == "passed" {
		status = "[green]OK"
	} else if repo.LastBuildState == "failed" {
		status = "[red]KO"
	}
	fmt.Printf(colorstring.Color(status) + "\t" + repo.Slug + "\n")
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package filters

import (
	"bufio"
	"errors"
	"fmt"
	"net"
	"net/http"
	"sync"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	auditinternal "k8s.io/apiserver/pkg/apis/audit"
	"k8s.io/apiserver/pkg/audit"
	"k8s.io/apiserver/pkg/audit/policy"
	"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
	"k8s.io/apiserver/pkg/endpoints/request"
)

// WithAudit decorates a http.Handler with audit logging information for all the
// requests coming to the server. Audit level is decided according to requests'
// attributes and audit policy. Logs are emitted to the audit sink to
// process events. If sink or audit policy is nil, no decoration takes place.
func WithAudit(handler http.Handler, requestContextMapper request.RequestContextMapper, sink audit.Sink, policy policy.Checker, longRunningCheck request.LongRunningRequestCheck) http.Handler {
	if sink == nil || policy == nil {
		return handler
	}
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		ctx, ev, err := createAuditEventAndAttachToContext(requestContextMapper, req, policy)
		if err != nil {
			utilruntime.HandleError(fmt.Errorf("failed to create audit event: %v", err))
			responsewriters.InternalError(w, req, errors.New("failed to create audit event"))
			return
		}
		if ev == nil || ctx == nil {
			handler.ServeHTTP(w, req)
			return
		}

		ev.Stage = auditinternal.StageRequestReceived
		processAuditEvent(sink, ev)

		// intercept the status code
		var longRunningSink audit.Sink
		if longRunningCheck != nil {
			ri, _ := request.RequestInfoFrom(ctx)
			if longRunningCheck(req, ri) {
				longRunningSink = sink
			}
		}
		respWriter := decorateResponseWriter(w, ev, longRunningSink)

		// send audit event when we leave this func, either via a panic or cleanly. In the case of long
		// running requests, this will be the second audit event.
		defer func() {
			if r := recover(); r != nil {
				defer panic(r)
				ev.Stage = auditinternal.StagePanic
				ev.ResponseStatus = &metav1.Status{
					Code:    http.StatusInternalServerError,
					Status:  metav1.StatusFailure,
					Reason:  metav1.StatusReasonInternalError,
					Message: fmt.Sprintf("APIServer panic'd: %v", r),
				}
				processAuditEvent(sink, ev)
				return
			}

			// if no StageResponseStarted event was sent b/c neither a status code nor a body was sent, fake it here
			fakedSuccessStatus := &metav1.Status{
				Code:    http.StatusOK,
				Status:  metav1.StatusSuccess,
				Message: "Connection closed early",
			}
			if ev.ResponseStatus == nil && longRunningSink != nil {
				ev.ResponseStatus = fakedSuccessStatus
				ev.Stage = auditinternal.StageResponseStarted
				processAuditEvent(longRunningSink, ev)
			}

			ev.Stage = auditinternal.StageResponseComplete
			if ev.ResponseStatus == nil {
				ev.ResponseStatus = fakedSuccessStatus
			}
			processAuditEvent(sink, ev)
		}()
		handler.ServeHTTP(respWriter, req)
	})
}

// createAuditEventAndAttachToContext is responsible for creating the audit event
// and attaching it to the appropriate request context. It returns:
// - context with audit event attached to it
// - created audit event
// - error if anything bad happened
func createAuditEventAndAttachToContext(requestContextMapper request.RequestContextMapper, req *http.Request, policy policy.Checker) (request.Context, *auditinternal.Event, error) {
	ctx, ok := requestContextMapper.Get(req)
	if !ok {
		return nil, nil, fmt.Errorf("no context found for request")
	}

	attribs, err := GetAuthorizerAttributes(ctx)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to GetAuthorizerAttributes: %v", err)
	}

	level := policy.Level(attribs)
	audit.ObservePolicyLevel(level)
	if level == auditinternal.LevelNone {
		// Don't audit.
		return nil, nil, nil
	}

	ev, err := audit.NewEventFromRequest(req, level, attribs)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to complete audit event from request: %v", err)
	}

	ctx = request.WithAuditEvent(ctx, ev)
	if err := requestContextMapper.Update(req, ctx); err != nil {
		return nil, nil, fmt.Errorf("failed to attach audit event to context: %v", err)
	}

	return ctx, ev, nil
}

func processAuditEvent(sink audit.Sink, ev *auditinternal.Event) {
	audit.ObserveEvent()
	sink.ProcessEvents(ev)
}

func decorateResponseWriter(responseWriter http.ResponseWriter, ev *auditinternal.Event, sink audit.Sink) http.ResponseWriter {
	delegate := &auditResponseWriter{
		ResponseWriter: responseWriter,
		event:          ev,
		sink:           sink,
	}

	// check if the ResponseWriter we're wrapping is the fancy one we need
	// or if the basic is sufficient
	_, cn := responseWriter.(http.CloseNotifier)
	_, fl := responseWriter.(http.Flusher)
	_, hj := responseWriter.(http.Hijacker)
	if cn && fl && hj {
		return &fancyResponseWriterDelegator{delegate}
	}
	return delegate
}

var _ http.ResponseWriter = &auditResponseWriter{}

// auditResponseWriter intercepts WriteHeader, sets it in the event. If the sink is set, it will
// create immediately an event (for long running requests).
type auditResponseWriter struct {
	http.ResponseWriter
	event *auditinternal.Event
	once  sync.Once
	sink  audit.Sink
}

func (a *auditResponseWriter) processCode(code int) {
	a.once.Do(func() {
		if a.event.ResponseStatus == nil {
			a.event.ResponseStatus = &metav1.Status{}
		}
		a.event.ResponseStatus.Code = int32(code)
		a.event.Stage = auditinternal.StageResponseStarted

		if a.sink != nil {
			processAuditEvent(a.sink, a.event)
		}
	})
}

func (a *auditResponseWriter) Write(bs []byte) (int, error) {
	a.processCode(http.StatusOK) // the Go library calls WriteHeader internally if no code was written yet. But this will go unnoticed for us
	return a.ResponseWriter.Write(bs)
}

func (a *auditResponseWriter) WriteHeader(code int) {
	a.processCode(code)
	a.ResponseWriter.WriteHeader(code)
}

// fancyResponseWriterDelegator implements http.CloseNotifier, http.Flusher and
// http.Hijacker which are needed to make certain http operation (e.g. watch, rsh, etc)
// working.
type fancyResponseWriterDelegator struct {
	*auditResponseWriter
}

func (f *fancyResponseWriterDelegator) CloseNotify() <-chan bool {
	return f.ResponseWriter.(http.CloseNotifier).CloseNotify()
}

func (f *fancyResponseWriterDelegator) Flush() {
	f.ResponseWriter.(http.Flusher).Flush()
}

func (f *fancyResponseWriterDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	// fake a response status before protocol switch happens
	f.processCode(http.StatusSwitchingProtocols)
	return f.ResponseWriter.(http.Hijacker).Hijack()
}

var _ http.CloseNotifier = &fancyResponseWriterDelegator{}
var _ http.Flusher = &fancyResponseWriterDelegator{}
var _ http.Hijacker = &fancyResponseWriterDelegator{}
<commit_msg>UPSTREAM: 52030: Fill in creationtimestamp in audit events<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package filters

import (
	"bufio"
	"errors"
	"fmt"
	"net"
	"net/http"
	"sync"
	"time"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	auditinternal "k8s.io/apiserver/pkg/apis/audit"
	"k8s.io/apiserver/pkg/audit"
	"k8s.io/apiserver/pkg/audit/policy"
	"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
	"k8s.io/apiserver/pkg/endpoints/request"
)

// WithAudit decorates a http.Handler with audit logging information for all the
// requests coming to the server. Audit level is decided according to requests'
// attributes and audit policy. Logs are emitted to the audit sink to
// process events. If sink or audit policy is nil, no decoration takes place.
func WithAudit(handler http.Handler, requestContextMapper request.RequestContextMapper, sink audit.Sink, policy policy.Checker, longRunningCheck request.LongRunningRequestCheck) http.Handler {
	if sink == nil || policy == nil {
		return handler
	}
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		ctx, ev, err := createAuditEventAndAttachToContext(requestContextMapper, req, policy)
		if err != nil {
			utilruntime.HandleError(fmt.Errorf("failed to create audit event: %v", err))
			responsewriters.InternalError(w, req, errors.New("failed to create audit event"))
			return
		}
		if ev == nil || ctx == nil {
			handler.ServeHTTP(w, req)
			return
		}

		ev.Stage = auditinternal.StageRequestReceived
		processAuditEvent(sink, ev)

		// intercept the status code
		var longRunningSink audit.Sink
		if longRunningCheck != nil {
			ri, _ := request.RequestInfoFrom(ctx)
			if longRunningCheck(req, ri) {
				longRunningSink = sink
			}
		}
		respWriter := decorateResponseWriter(w, ev, longRunningSink)

		// send audit event when we leave this func, either via a panic or cleanly. In the case of long
		// running requests, this will be the second audit event.
		defer func() {
			if r := recover(); r != nil {
				defer panic(r)
				ev.Stage = auditinternal.StagePanic
				ev.ResponseStatus = &metav1.Status{
					Code:    http.StatusInternalServerError,
					Status:  metav1.StatusFailure,
					Reason:  metav1.StatusReasonInternalError,
					Message: fmt.Sprintf("APIServer panic'd: %v", r),
				}
				processAuditEvent(sink, ev)
				return
			}

			// if no StageResponseStarted event was sent b/c neither a status code nor a body was sent, fake it here
			fakedSuccessStatus := &metav1.Status{
				Code:    http.StatusOK,
				Status:  metav1.StatusSuccess,
				Message: "Connection closed early",
			}
			if ev.ResponseStatus == nil && longRunningSink != nil {
				ev.ResponseStatus = fakedSuccessStatus
				ev.Stage = auditinternal.StageResponseStarted
				processAuditEvent(longRunningSink, ev)
			}

			ev.Stage = auditinternal.StageResponseComplete
			if ev.ResponseStatus == nil {
				ev.ResponseStatus = fakedSuccessStatus
			}
			processAuditEvent(sink, ev)
		}()
		handler.ServeHTTP(respWriter, req)
	})
}

// createAuditEventAndAttachToContext is responsible for creating the audit event
// and attaching it to the appropriate request context. It returns:
// - context with audit event attached to it
// - created audit event
// - error if anything bad happened
func createAuditEventAndAttachToContext(requestContextMapper request.RequestContextMapper, req *http.Request, policy policy.Checker) (request.Context, *auditinternal.Event, error) {
	ctx, ok := requestContextMapper.Get(req)
	if !ok {
		return nil, nil, fmt.Errorf("no context found for request")
	}

	attribs, err := GetAuthorizerAttributes(ctx)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to GetAuthorizerAttributes: %v", err)
	}

	level := policy.Level(attribs)
	audit.ObservePolicyLevel(level)
	if level == auditinternal.LevelNone {
		// Don't audit.
		return nil, nil, nil
	}

	ev, err := audit.NewEventFromRequest(req, level, attribs)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to complete audit event from request: %v", err)
	}

	ctx = request.WithAuditEvent(ctx, ev)
	if err := requestContextMapper.Update(req, ctx); err != nil {
		return nil, nil, fmt.Errorf("failed to attach audit event to context: %v", err)
	}

	return ctx, ev, nil
}

func processAuditEvent(sink audit.Sink, ev *auditinternal.Event) {
	ev.CreationTimestamp = metav1.NewTime(time.Now())
	audit.ObserveEvent()
	sink.ProcessEvents(ev)
}

func decorateResponseWriter(responseWriter http.ResponseWriter, ev *auditinternal.Event, sink audit.Sink) http.ResponseWriter {
	delegate := &auditResponseWriter{
		ResponseWriter: responseWriter,
		event:          ev,
		sink:           sink,
	}

	// check if the ResponseWriter we're wrapping is the fancy one we need
	// or if the basic is sufficient
	_, cn := responseWriter.(http.CloseNotifier)
	_, fl := responseWriter.(http.Flusher)
	_, hj := responseWriter.(http.Hijacker)
	if cn && fl && hj {
		return &fancyResponseWriterDelegator{delegate}
	}
	return delegate
}

var _ http.ResponseWriter = &auditResponseWriter{}

// auditResponseWriter intercepts WriteHeader, sets it in the event. If the sink is set, it will
// create immediately an event (for long running requests).
type auditResponseWriter struct {
	http.ResponseWriter
	event *auditinternal.Event
	once  sync.Once
	sink  audit.Sink
}

func (a *auditResponseWriter) processCode(code int) {
	a.once.Do(func() {
		if a.event.ResponseStatus == nil {
			a.event.ResponseStatus = &metav1.Status{}
		}
		a.event.ResponseStatus.Code = int32(code)
		a.event.Stage = auditinternal.StageResponseStarted

		if a.sink != nil {
			processAuditEvent(a.sink, a.event)
		}
	})
}

func (a *auditResponseWriter) Write(bs []byte) (int, error) {
	a.processCode(http.StatusOK) // the Go library calls WriteHeader internally if no code was written yet. But this will go unnoticed for us
	return a.ResponseWriter.Write(bs)
}

func (a *auditResponseWriter) WriteHeader(code int) {
	a.processCode(code)
	a.ResponseWriter.WriteHeader(code)
}

// fancyResponseWriterDelegator implements http.CloseNotifier, http.Flusher and
// http.Hijacker which are needed to make certain http operation (e.g. watch, rsh, etc)
// working.
type fancyResponseWriterDelegator struct {
	*auditResponseWriter
}

func (f *fancyResponseWriterDelegator) CloseNotify() <-chan bool {
	return f.ResponseWriter.(http.CloseNotifier).CloseNotify()
}

func (f *fancyResponseWriterDelegator) Flush() {
	f.ResponseWriter.(http.Flusher).Flush()
}

func (f *fancyResponseWriterDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	// fake a response status before protocol switch happens
	f.processCode(http.StatusSwitchingProtocols)
	return f.ResponseWriter.(http.Hijacker).Hijack()
}

var _ http.CloseNotifier = &fancyResponseWriterDelegator{}
var _ http.Flusher = &fancyResponseWriterDelegator{}
var _ http.Hijacker = &fancyResponseWriterDelegator{}
<|endoftext|>


<commit_before>// Package neat implements NeuroEvolution of Augmenting Topologies (NEAT) method which can be used to evolve
// Artificial Neural Networks to perform specific task using genetic algorithms.
package neat

import "math/rand"

// The number of parameters used in neurons that learn through habituation,
// sensitization, or Hebbian-type processes
const Num_trait_params = 8

// The NEAT execution context holding common configuration parameters, etc.
type NeatContext struct {
	// Prob. of mutating a single trait param
	TraitParamMutProb      float64
	// Power of mutation on a single trait param
	TraitMutationPower     float64
	// Amount that mutation_num changes for a trait change inside a link
	LinkTraitMutSig        float64
	// Amount a mutation_num changes on a link connecting a node that changed its trait
	NodeTraitMutSig        float64
	// The power of a linkweight mutation
	WeightMutPower         float64

	// These 3 global coefficients are used to determine the formula for
	// computing the compatibility between 2 genomes.  The formula is:
	// disjoint_coeff * pdg + excess_coeff * peg + mutdiff_coeff * mdmg.
	// See the compatibility method in the Genome class for more info
	// They can be thought of as the importance of disjoint Genes,
	// excess Genes, and parametric difference between Genes of the
	// same function, respectively.
	DisjointCoeff          float64
	ExcessCoeff            float64
	MutdiffCoeff           float64

	// This global tells compatibility threshold under which
	// two Genomes are considered the same species */
	CompatThreshold        float64

	/* Globals involved in the epoch cycle - mating, reproduction, etc.. */

	// How much does age matter?
	AgeSignificance        float64
	// Percent of ave fitness for survival
	SurvivalThresh         float64

	// Probabilities of a non-mating reproduction
	MutateOnlyProb         float64
	MutateRandomTraitProb  float64
	MutateLinkTraitProb    float64
	MutateNodeTraitProb    float64
	MutateLinkWeightsProb  float64
	MutateToggleEnableProb float64
	MutateGeneReenableProb float64
	MutateAddNodeProb      float64
	MutateAddLinkProb      float64

	// Probabilities of a mate being outside species
	InterspeciesMateRate   float64
	MateMultipointProb     float64
	MateMultipointAvgProb  float64
	MateSinglepointProb    float64

	// Prob. of mating without mutation
	MateOnlyProb           float64
	// Probability of forcing selection of ONLY links that are naturally recurrent
	RecurOnlyProb          float64

	// Size of population
	PopSize                int
	// Age where Species starts to be penalized
	DropOffAge             int
	// Number of tries mutate_add_link will attempt to find an open link
	NewLinkTries           int

	// Tells to print population to file every n generations
	PrintEvery             int

	// The number of babies to siphen off to the champions
	BabiesStolen           int

	// The number of runs to average over in an experiment
	Num_runs               int
}

// Returns
func RandPosNeg() int32 {
	v := rand.Int()
	if (v % 2) == 0 {
		return -1
	} else {
		return 1
	}
}
<commit_msg>Implemented debug console logging function<commit_after>// Package neat implements NeuroEvolution of Augmenting Topologies (NEAT) method which can be used to evolve
// Artificial Neural Networks to perform specific task using genetic algorithms.
package neat

import (
	"math/rand"
	"fmt"
)

// The number of parameters used in neurons that learn through habituation,
// sensitization, or Hebbian-type processes
const Num_trait_params = 8

// The NEAT execution context holding common configuration parameters, etc.
type NeatContext struct {
	// Prob. of mutating a single trait param
	TraitParamMutProb      float64
	// Power of mutation on a single trait param
	TraitMutationPower     float64
	// Amount that mutation_num changes for a trait change inside a link
	LinkTraitMutSig        float64
	// Amount a mutation_num changes on a link connecting a node that changed its trait
	NodeTraitMutSig        float64
	// The power of a linkweight mutation
	WeightMutPower         float64

	// These 3 global coefficients are used to determine the formula for
	// computing the compatibility between 2 genomes.  The formula is:
	// disjoint_coeff * pdg + excess_coeff * peg + mutdiff_coeff * mdmg.
	// See the compatibility method in the Genome class for more info
	// They can be thought of as the importance of disjoint Genes,
	// excess Genes, and parametric difference between Genes of the
	// same function, respectively.
	DisjointCoeff          float64
	ExcessCoeff            float64
	MutdiffCoeff           float64

	// This global tells compatibility threshold under which
	// two Genomes are considered the same species */
	CompatThreshold        float64

	/* Globals involved in the epoch cycle - mating, reproduction, etc.. */

	// How much does age matter?
	AgeSignificance        float64
	// Percent of ave fitness for survival
	SurvivalThresh         float64

	// Probabilities of a non-mating reproduction
	MutateOnlyProb         float64
	MutateRandomTraitProb  float64
	MutateLinkTraitProb    float64
	MutateNodeTraitProb    float64
	MutateLinkWeightsProb  float64
	MutateToggleEnableProb float64
	MutateGeneReenableProb float64
	MutateAddNodeProb      float64
	MutateAddLinkProb      float64

	// Probabilities of a mate being outside species
	InterspeciesMateRate   float64
	MateMultipointProb     float64
	MateMultipointAvgProb  float64
	MateSinglepointProb    float64

	// Prob. of mating without mutation
	MateOnlyProb           float64
	// Probability of forcing selection of ONLY links that are naturally recurrent
	RecurOnlyProb          float64

	// Size of population
	PopSize        int
	// Age where Species starts to be penalized
	DropOffAge     int
	// Number of tries mutate_add_link will attempt to find an open link
	NewLinkTries   int

	// Tells to print population to file every n generations
	PrintEvery     int

	// The number of babies to siphen off to the champions
	BabiesStolen   int

	// The number of runs to average over in an experiment
	Num_runs       int

	// The flag to indicate whether to print additional debugging info
	IsDebugEnabled bool
}

func (c *NeatContext) DebugLog(rec string) {
	if c.IsDebugEnabled {
		fmt.Println(rec)
	}
}

// Returns
func RandPosNeg() int32 {
	v := rand.Int()
	if (v % 2) == 0 {
		return -1
	} else {
		return 1
	}
}
<|endoftext|>


<commit_before>package common

import "github.com/webx-top/com"

var (
	boolFlags = []string{`Y`, `N`}
	contypes  = []string{`html`, `markdown`, `text`}
)

func GetBoolFlag(value string, defaults ...string) string {
	if len(value) == 0 || !com.InSlice(value, boolFlags) {
		if len(defaults) > 0 {
			return defaults[0]
		}
		return `N`
	}
	return value
}

func GetContype(value string, defaults ...string) string {
	if len(value) == 0 || !com.InSlice(value, contypes) {
		if len(defaults) > 0 {
			return defaults[0]
		}
		return `text`
	}
	return value
}

func GetEnumValue(enums []string, value string, defaults string) string {
	if len(value) == 0 || !com.InSlice(value, enums) {
		return defaults
	}
	return value
}
<commit_msg>update<commit_after>package common

import "github.com/webx-top/com"

var (
	boolFlags = []string{`Y`, `N`}
	contypes  = []string{`html`, `markdown`, `text`}
)

func GetBoolFlag(value string, defaults ...string) string {
	if len(value) == 0 || !com.InSlice(value, boolFlags) {
		if len(defaults) > 0 {
			return defaults[0]
		}
		return `N`
	}
	return value
}

func BoolToFlag(v bool) string {
	if v {
		return `Y`
	}
	return `N`
}

func FlagToBool(v string) bool {
	return v == `Y`
}

func GetContype(value string, defaults ...string) string {
	if len(value) == 0 || !com.InSlice(value, contypes) {
		if len(defaults) > 0 {
			return defaults[0]
		}
		return `text`
	}
	return value
}

func GetEnumValue(enums []string, value string, defaults string) string {
	if len(value) == 0 || !com.InSlice(value, enums) {
		return defaults
	}
	return value
}
<|endoftext|>


<commit_before>package dhcp6

import (
	"fmt"
	"net"
	"encoding/binary"
	"bytes"
	"golang.org/x/tools/go/gcimporter15/testdata"
)

type MessageType uint8

const (
	MsgSolicit MessageType = iota + 1
	MsgAdvertise
	MsgRequest
	MsgConfirm
	MsgRenew
	MsgRebind
	MsgReply
	MsgRelease
	MsgDecline
	MsgReconfigure
	MsgInformationRequest
	MsgRelayForw
	MsgRelayRepl
)

type Packet struct {
	Type          MessageType
	TransactionID [3]byte
	Options       Options
}

func MakePacket(bs []byte, len int) (*Packet, error) {
	options, err := MakeOptions(bs[4:]) // 4:len?
	if err != nil {
		return nil, fmt.Errorf("packet has malformed options section: %s", err)
	}
	ret := &Packet{Type: MessageType(bs[0]), Options: options}
	copy(ret.TransactionID[:], bs[1:4])
	return ret, nil
}

func (p *Packet) Marshal() ([]byte, error) {
	marshalled_options, err := p.Options.Marshal()
	if err != nil {
		return nil, fmt.Errorf("packet has malformed options section: %s", err)
	}

	ret := make([]byte, len(marshalled_options) + 4, len(marshalled_options) + 4)
	ret[0] = byte(MsgAdvertise)
	copy(ret[1:], p.TransactionID[:])
	copy(ret[4:], marshalled_options)

	return ret, nil
}

func (p *Packet) BuildResponse(serverDuid []byte) *Packet {
	switch p.Type {
	case MsgSolicit:
		return p.BuildMsgAdvertise(serverDuid)
	case MsgRequest:
		return p.BuildMsgReply(serverDuid)
	case MsgInformationRequest:
		return p.BuildMsgInformationRequestReply(serverDuid)
	case MsgRelease:
		return p.BuildMsgReleaseReply(serverDuid)
	default:
		return nil
	}
}

func (p *Packet) BuildMsgAdvertise(serverDuid []byte) *Packet {
	in_options := p.Options
	ret_options := make(Options)

	ret_options.AddOption(&Option{Id: OptClientId, Length: uint16(len(in_options[OptClientId].Value)), Value: in_options[OptClientId].Value})
	ret_options.AddOption(MakeIaNaOption(in_options[OptIaNa].Value[0:4], 0, 0,
			MakeIaAddrOption(net.ParseIP("2001:db8:f00f:cafe::99"), 27000, 43200)))
	ret_options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverDuid)), Value: serverDuid})

	if 0x10 == binary.BigEndian.Uint16(in_options[OptClientArchType].Value) { // HTTPClient
		ret_options.AddOption(&Option{Id: OptVendorClass, Length: 16, Value: []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116}}) // HTTPClient
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/bootx64.efi")})
	} else {
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/script.ipxe")})
	}
//	ret_options.AddOption(OptRecursiveDns, net.ParseIP("2001:db8:f00f:cafe::1"))
	//ret_options.AddOption(OptBootfileParam, []byte("http://")
	//ret.Options[OptPreference] = [][]byte("http://")

	return &Packet{Type: MsgAdvertise, TransactionID: p.TransactionID, Options: ret_options}
}

// TODO: OptClientArchType may not be present

func (p *Packet) BuildMsgReply(serverDuid []byte) *Packet {
	in_options := p.Options
	ret_options := make(Options)

	ret_options.AddOption(&Option{Id: OptClientId, Length: uint16(len(in_options[OptClientId].Value)), Value: in_options[OptClientId].Value})
	ret_options.AddOption(MakeIaNaOption(in_options[OptIaNa].Value[0:4], 0, 0,
		MakeIaAddrOption(net.ParseIP("2001:db8:f00f:cafe::99"), 27000, 43200)))
	ret_options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverDuid)), Value: serverDuid})
	//	ret_options.AddOption(OptRecursiveDns, net.ParseIP("2001:db8:f00f:cafe::1"))
	if 0x10 == binary.BigEndian.Uint16(in_options[OptClientArchType].Value) { // HTTPClient
		ret_options.AddOption(&Option{Id: OptVendorClass, Length: 16, Value: []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116}}) // HTTPClient
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/bootx64.efi")})
	} else {
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/script.ipxe")})
	}

	return &Packet{Type: MsgReply, TransactionID: p.TransactionID, Options: ret_options}
}

func (p *Packet) BuildMsgInformationRequestReply(serverDuid []byte) *Packet {
	in_options := p.Options
	ret_options := make(Options)

	ret_options.AddOption(&Option{Id: OptClientId, Length: uint16(len(in_options[OptClientId].Value)), Value: in_options[OptClientId].Value})
	ret_options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverDuid)), Value: serverDuid})
	//	ret_options.AddOption(OptRecursiveDns, net.ParseIP("2001:db8:f00f:cafe::1"))
	if 0x10 == binary.BigEndian.Uint16(in_options[OptClientArchType].Value) { // HTTPClient
		ret_options.AddOption(&Option{Id: OptVendorClass, Length: 16, Value: []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116}}) // HTTPClient
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/bootx64.efi")})
	} else {
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/script.ipxe")})
	}
	return &Packet{Type: MsgReply, TransactionID: p.TransactionID, Options: ret_options}
}

func (p *Packet) BuildMsgReleaseReply(serverDuid []byte) *Packet {
	in_options := p.Options
	ret_options := make(Options)

	ret_options.AddOption(&Option{Id: OptClientId, Length: uint16(len(in_options[OptClientId].Value)), Value: in_options[OptClientId].Value})
	ret_options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverDuid)), Value: serverDuid})
	v := make([]byte, 19, 19)
	copy(v[2:], []byte("Release received."))
	ret_options.AddOption(&Option{Id: OptStatusCode, Length: uint16(len(v)), Value: v})

	return &Packet{Type: MsgReply, TransactionID: p.TransactionID, Options: ret_options}
}

func (p *Packet) ShouldDiscard(serverDuid []byte) error {
	switch p.Type {
	case MsgSolicit:
		return ShouldDiscardSolicit(p)
	case MsgRequest:
		return ShouldDiscardRequest(p, serverDuid)
	case MsgInformationRequest:
		return ShouldDiscardInformationRequest(p, serverDuid)
	case MsgRelease:
		return nil // FIX ME!
	default:
		return fmt.Errorf("Unknown packet")
	}
}

func ShouldDiscardSolicit(p *Packet) error {
	options := p.Options
	if !options.RequestedBootFileUrlOption() {
		return fmt.Errorf("'Solicit' packet doesn't have file url option")
	}
	if !options.HasClientId() {
		return fmt.Errorf("'Solicit' packet has no client id option")
	}
	if options.HasServerId() {
		return fmt.Errorf("'Solicit' packet has server id option")
	}
	return nil
}

func ShouldDiscardRequest(p *Packet, serverDuid []byte) error {
	options := p.Options
	if !options.RequestedBootFileUrlOption() {
		return fmt.Errorf("'Request' packet doesn't have file url option")
	}
	if !options.HasClientId() {
		return fmt.Errorf("'Request' packet has no client id option")
	}
	if !options.HasServerId() {
		return fmt.Errorf("'Request' packet has no server id option")
	}
	if bytes.Compare(options[OptServerId].Value, serverDuid) != 0 {
		return fmt.Errorf("'Request' packet's server id option (%d) is different from ours (%d)", options[OptServerId].Value, serverDuid)
	}
	return nil
}

func ShouldDiscardInformationRequest(p *Packet, serverDuid []byte) error {
	options := p.Options
	if !options.RequestedBootFileUrlOption() {
		return fmt.Errorf("'Information-request' packet doesn't have boot file url option")
	}
	if options.HasIaNa() || options.HasIaTa() {
		return fmt.Errorf("'Information-request' packet has an IA option present")
	}
	if options.HasServerId() && (bytes.Compare(options[OptServerId].Value, serverDuid) != 0) {
		return fmt.Errorf("'Information-request' packet's server id option (%d) is different from ours (%d)", options[OptServerId].Value, serverDuid)
	}
	return nil
}<commit_msg>and moar testability changes<commit_after>package dhcp6

import (
	"fmt"
	"net"
	"encoding/binary"
	"bytes"
	"golang.org/x/tools/go/gcimporter15/testdata"
)

type MessageType uint8

const (
	MsgSolicit MessageType = iota + 1
	MsgAdvertise
	MsgRequest
	MsgConfirm
	MsgRenew
	MsgRebind
	MsgReply
	MsgRelease
	MsgDecline
	MsgReconfigure
	MsgInformationRequest
	MsgRelayForw
	MsgRelayRepl
)

type Packet struct {
	Type          MessageType
	TransactionID [3]byte
	Options       Options
}

func MakePacket(bs []byte, len int) (*Packet, error) {
	options, err := MakeOptions(bs[4:]) // 4:len?
	if err != nil {
		return nil, fmt.Errorf("packet has malformed options section: %s", err)
	}
	ret := &Packet{Type: MessageType(bs[0]), Options: options}
	copy(ret.TransactionID[:], bs[1:4])
	return ret, nil
}

func (p *Packet) Marshal() ([]byte, error) {
	marshalled_options, err := p.Options.Marshal()
	if err != nil {
		return nil, fmt.Errorf("packet has malformed options section: %s", err)
	}

	ret := make([]byte, len(marshalled_options) + 4, len(marshalled_options) + 4)
	ret[0] = byte(MsgAdvertise)
	copy(ret[1:], p.TransactionID[:])
	copy(ret[4:], marshalled_options)

	return ret, nil
}

func (p *Packet) BuildResponse(serverDuid []byte) *Packet {
	transactionId := p.TransactionID
	clientId := in_options[OptClientId].Value
	iaNaId := in_options[OptIaNa].Value[0:4]
	clientArchType := in_options[OptClientArchType].Value

	switch p.Type {
	case MsgSolicit:
		return MakeMsgAdvertise(transactionId, serverDuid, clientId, iaNaId, clientArchType)
	case MsgRequest:
		return MakeMsgReply(transactionId, serverDuid, clientId, iaNaId, clientArchType)
	case MsgInformationRequest:
		return MakeMsgInformationRequestReply(transactionId, serverDuid, clientId, clientArchType)
	case MsgRelease:
		return MakeMsgReleaseReply(transactionId, serverDuid, clientId)
	default:
		return nil
	}
}

func MakeMsgAdvertise(transactionId [3]byte, serverDuid, clientId, iaId, clientArchType []byte) *Packet {
	ret_options := make(Options)

	ret_options.AddOption(&Option{Id: OptClientId, Length: uint16(len(clientId)), Value: clientId})
	ret_options.AddOption(MakeIaNaOption(iaId, 0, 0,
		MakeIaAddrOption(net.ParseIP("2001:db8:f00f:cafe::99"), 27000, 43200)))
	ret_options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverDuid)), Value: serverDuid})

	if 0x10 == binary.BigEndian.Uint16(clientArchType) { // HTTPClient
		ret_options.AddOption(&Option{Id: OptVendorClass, Length: 16, Value: []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116}}) // HTTPClient
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/bootx64.efi")})
	} else {
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/script.ipxe")})
	}
	//	ret_options.AddOption(OptRecursiveDns, net.ParseIP("2001:db8:f00f:cafe::1"))
	//ret_options.AddOption(OptBootfileParam, []byte("http://")
	//ret.Options[OptPreference] = [][]byte("http://")

	return &Packet{Type: MsgAdvertise, TransactionID: transactionId, Options: ret_options}
}

// TODO: OptClientArchType may not be present

func MakeMsgReply(transactionId [3]byte, serverDuid, clientId, iaId, clientArchType []byte) *Packet {
	ret_options := make(Options)

	ret_options.AddOption(&Option{Id: OptClientId, Length: uint16(len(clientId)), Value: clientId})
	ret_options.AddOption(MakeIaNaOption(iaId, 0, 0,
		MakeIaAddrOption(net.ParseIP("2001:db8:f00f:cafe::99"), 27000, 43200)))
	ret_options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverDuid)), Value: serverDuid})
	//	ret_options.AddOption(OptRecursiveDns, net.ParseIP("2001:db8:f00f:cafe::1"))
	if 0x10 == binary.BigEndian.Uint16(clientArchType) { // HTTPClient
		ret_options.AddOption(&Option{Id: OptVendorClass, Length: 16, Value: []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116}}) // HTTPClient
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/bootx64.efi")})
	} else {
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/script.ipxe")})
	}

	return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options}
}

func MakeMsgInformationRequestReply(transactionId [3]byte, serverDuid, clientId, clientArchType []byte) *Packet {
	ret_options := make(Options)
	ret_options.AddOption(&Option{Id: OptClientId, Length: uint16(len(clientId)), Value: clientId})
	ret_options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverDuid)), Value: serverDuid})
	//	ret_options.AddOption(OptRecursiveDns, net.ParseIP("2001:db8:f00f:cafe::1"))
	if 0x10 == binary.BigEndian.Uint16(clientArchType) { // HTTPClient
		ret_options.AddOption(&Option{Id: OptVendorClass, Length: 16, Value: []byte{0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116}}) // HTTPClient
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/bootx64.efi")})
	} else {
		ret_options.AddOption(&Option{Id: OptBootfileUrl, Length: 42, Value: []byte("http://[2001:db8:f00f:cafe::4]/script.ipxe")})
	}

	return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options}
}

func MakeMsgReleaseReply(transactionId [3]byte, serverDuid, clientId []byte) *Packet {
	ret_options := make(Options)

	ret_options.AddOption(&Option{Id: OptClientId, Length: uint16(len(clientId)), Value: clientId})
	ret_options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverDuid)), Value: serverDuid})
	v := make([]byte, 19, 19)
	copy(v[2:], []byte("Release received."))
	ret_options.AddOption(&Option{Id: OptStatusCode, Length: uint16(len(v)), Value: v})

	return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options}
}

func (p *Packet) ShouldDiscard(serverDuid []byte) error {
	switch p.Type {
	case MsgSolicit:
		return ShouldDiscardSolicit(p)
	case MsgRequest:
		return ShouldDiscardRequest(p, serverDuid)
	case MsgInformationRequest:
		return ShouldDiscardInformationRequest(p, serverDuid)
	case MsgRelease:
		return nil // FIX ME!
	default:
		return fmt.Errorf("Unknown packet")
	}
}

func ShouldDiscardSolicit(p *Packet) error {
	options := p.Options
	if !options.RequestedBootFileUrlOption() {
		return fmt.Errorf("'Solicit' packet doesn't have file url option")
	}
	if !options.HasClientId() {
		return fmt.Errorf("'Solicit' packet has no client id option")
	}
	if options.HasServerId() {
		return fmt.Errorf("'Solicit' packet has server id option")
	}
	return nil
}

func ShouldDiscardRequest(p *Packet, serverDuid []byte) error {
	options := p.Options
	if !options.RequestedBootFileUrlOption() {
		return fmt.Errorf("'Request' packet doesn't have file url option")
	}
	if !options.HasClientId() {
		return fmt.Errorf("'Request' packet has no client id option")
	}
	if !options.HasServerId() {
		return fmt.Errorf("'Request' packet has no server id option")
	}
	if bytes.Compare(options[OptServerId].Value, serverDuid) != 0 {
		return fmt.Errorf("'Request' packet's server id option (%d) is different from ours (%d)", options[OptServerId].Value, serverDuid)
	}
	return nil
}

func ShouldDiscardInformationRequest(p *Packet, serverDuid []byte) error {
	options := p.Options
	if !options.RequestedBootFileUrlOption() {
		return fmt.Errorf("'Information-request' packet doesn't have boot file url option")
	}
	if options.HasIaNa() || options.HasIaTa() {
		return fmt.Errorf("'Information-request' packet has an IA option present")
	}
	if options.HasServerId() && (bytes.Compare(options[OptServerId].Value, serverDuid) != 0) {
		return fmt.Errorf("'Information-request' packet's server id option (%d) is different from ours (%d)", options[OptServerId].Value, serverDuid)
	}
	return nil
}<|endoftext|>


<commit_before>// Package disco controls interaction with the rqlite Discovery service
package disco

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

// Response represents the response returned by a Discovery Service.
type Response struct {
	CreatedAt string   `json:"created_at"`
	DiscoID   string   `json:"disco_id"`
	Nodes     []string `json:"nodes"`
}

// Client provides a Discovery Service client.
type Client struct {
	url    string
	logger *log.Logger
}

// New returns an initialized Discovery Service client.
func New(url string) *Client {
	return &Client{
		url:    url,
		logger: log.New(os.Stderr, "[discovery] ", log.LstdFlags),
	}
}

// URL returns the Discovery Service URL used by this client.
func (c *Client) URL() string {
	return c.url
}

// Register attempts to register with the Discovery Service, using the given
// proto and address.
func (c *Client) Register(id, addr string) (*Response, error) {
	m := map[string]string{
		"addr": addr,
	}

	url := c.registrationURL(c.url, id)
	client := &http.Client{}
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		return http.ErrUseLastResponse
	}

	for {
		b, err := json.Marshal(m)
		if err != nil {
			return nil, err
		}

		c.logger.Printf("discovery client attempting registration of %s at %s", addr, url)
		resp, err := client.Post(url, "application-type/json", bytes.NewReader(b))
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()

		b, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}

		switch resp.StatusCode {
		case http.StatusOK:
			r := &Response{}
			if err := json.Unmarshal(b, r); err != nil {
				return nil, err
			}
			c.logger.Printf("discovery client successfully registered %s at %s", addr, url)
			return r, nil
		case http.StatusMovedPermanently:
			url = resp.Header.Get("location")
			c.logger.Println("discovery client redirecting to", url)
			continue
		default:
			return nil, errors.New(resp.Status)
		}
	}
}

func (c *Client) registrationURL(url, id string) string {
	return fmt.Sprintf("%s/%s", url, id)
}
<commit_msg>Revert client comment<commit_after>// Package disco controls interaction with the rqlite Discovery service
package disco

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

// Response represents the response returned by a Discovery Service.
type Response struct {
	CreatedAt string   `json:"created_at"`
	DiscoID   string   `json:"disco_id"`
	Nodes     []string `json:"nodes"`
}

// Client provides a Discovery Service client.
type Client struct {
	url    string
	logger *log.Logger
}

// New returns an initialized Discovery Service client.
func New(url string) *Client {
	return &Client{
		url:    url,
		logger: log.New(os.Stderr, "[discovery] ", log.LstdFlags),
	}
}

// URL returns the Discovery Service URL used by this client.
func (c *Client) URL() string {
	return c.url
}

// Register attempts to register with the Discovery Service, using the given
// address.
func (c *Client) Register(id, addr string) (*Response, error) {
	m := map[string]string{
		"addr": addr,
	}

	url := c.registrationURL(c.url, id)
	client := &http.Client{}
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		return http.ErrUseLastResponse
	}

	for {
		b, err := json.Marshal(m)
		if err != nil {
			return nil, err
		}

		c.logger.Printf("discovery client attempting registration of %s at %s", addr, url)
		resp, err := client.Post(url, "application-type/json", bytes.NewReader(b))
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()

		b, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}

		switch resp.StatusCode {
		case http.StatusOK:
			r := &Response{}
			if err := json.Unmarshal(b, r); err != nil {
				return nil, err
			}
			c.logger.Printf("discovery client successfully registered %s at %s", addr, url)
			return r, nil
		case http.StatusMovedPermanently:
			url = resp.Header.Get("location")
			c.logger.Println("discovery client redirecting to", url)
			continue
		default:
			return nil, errors.New(resp.Status)
		}
	}
}

func (c *Client) registrationURL(url, id string) string {
	return fmt.Sprintf("%s/%s", url, id)
}
<|endoftext|>