<commit_before>package svg

import (
	"strconv"

	"github.com/tdewolff/minify"
	"github.com/tdewolff/parse"
)

type PathData struct {
	x, y   float64
	coords [][]byte

	alterBuffer []byte
	coordBuffer []byte
}

func ShortenPathData(b []byte, p *PathData) []byte {
	var x0, y0 float64
	var cmd byte

	p.x, p.y = 0.0, 0.0
	p.coords = p.coords[:0]

	j := 0
	for i := 0; i < len(b); i++ {
		c := b[i]
		if c == ' ' || c == ',' || c == '\n' || c == '\r' || c == '\t' {
			continue
		} else if c >= 'A' { // any command
			if cmd == 0 {
				cmd = c
			} else if c != cmd {
				x1, y1 := x0, y0
				if cmd == 'M' {
					x1 = toFloat(p.coords[len(p.coords)-2])
					y1 = toFloat(p.coords[len(p.coords)-1])
				} else if cmd == 'm' {
					x1 += toFloat(p.coords[len(p.coords)-2])
					y1 += toFloat(p.coords[len(p.coords)-1])
				}
				j += p.copyInstruction(b[j:], cmd)
				if cmd == 'M' || cmd == 'm' || cmd == 'Z' || cmd == 'z' {
					x0 = x1
					y0 = y1
					p.x = x0
					p.y = y0
				}
				cmd = c
				p.coords = p.coords[:0]
			}
		} else if n := parse.Number(b[i:]); n > 0 {
			p.coords = append(p.coords, minify.Number(b[i:i+n]))
			i += n - 1
		}
	}
	j += p.copyInstruction(b[j:], cmd)
	return b[:j]
}

func (p *PathData) copyInstruction(b []byte, cmd byte) int {
	n := len(p.coords)
	cmdIsRelative := cmd >= 'a'

	// get new cursor coordinates
	ax, ay := p.x, p.y
	if n >= 2 && (cmd == 'L' || cmd == 'l' || cmd == 'C' || cmd == 'c' || cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q' || cmd == 'T' || cmd == 't' || cmd == 'A' || cmd == 'a') {
		ax = toFloat(p.coords[n-2])
		ay = toFloat(p.coords[n-1])
	} else if n >= 1 && (cmd == 'H' || cmd == 'h' || cmd == 'V' || cmd == 'v') {
		if cmd == 'H' || cmd == 'h' {
			ax = toFloat(p.coords[n-1])
		} else {
			ay = toFloat(p.coords[n-1])
		}
	}

	// make an alternative path with absolute/relative altered
	cmdAlter := cmd - 'A' + 'a'
	dx, dy := -p.x, -p.y
	if cmdIsRelative {
		cmdAlter = cmd - 'a' + 'A'
		dx, dy = p.x, p.y
	}
	p.alterBuffer = p.copyAlteredInstruction(p.alterBuffer[:0], cmdAlter, dx, dy)

	// choose shortest, relative or absolute path?
	j := p.copyCurrentInstruction(b, cmd)
	jAlter := len(p.alterBuffer)
	if jAlter < j {
		j = jAlter
		copy(b, p.alterBuffer)
	}

	// set new cursor coordinates
	if cmdIsRelative {
		p.x += ax
		p.y += ay
	} else {
		p.x = ax
		p.y = ay
	}
	return j
}

func (p *PathData) copyCurrentInstruction(b []byte, cmd byte) int {
	prevDigit := false
	prevDigitRequiresSpace := true

	b[0] = cmd
	j := 1
	for _, coord := range p.coords {
		if prevDigit && (coord[0] >= '0' && coord[0] <= '9' || coord[0] == '.' && prevDigitRequiresSpace) {
			b[j] = ' '
			j++
		}
		prevDigit = true
		prevDigitRequiresSpace = true
		for _, c := range coord {
			if c == '.' || c == 'e' || c == 'E' {
				prevDigitRequiresSpace = false
				break
			}
		}
		j += copy(b[j:], coord)
	}
	return j
}

func (p *PathData) copyAlteredInstruction(b []byte, cmd byte, dx, dy float64) []byte {
	prevDigit := false
	prevDigitRequiresSpace := true

	b = append(b, cmd)
	for i, coord := range p.coords {
		f := toFloat(coord)
		if cmd == 'L' || cmd == 'l' || cmd == 'C' || cmd == 'c' || cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q' || cmd == 'T' || cmd == 't' || cmd == 'M' || cmd == 'm' {
			if i%2 == 0 {
				f += dx
			} else {
				f += dy
			}
		} else if cmd == 'H' || cmd == 'h' {
			f += dx
		} else if cmd == 'V' || cmd == 'v' {
			f += dy
		} else if cmd == 'A' || cmd == 'a' {
			if i%7 == 5 {
				f += dx
			} else if i%7 == 6 {
				f += dy
			}
		} else {
			continue
		}
		p.coordBuffer = strconv.AppendFloat(p.coordBuffer[:0], f, 'f', -1, 32)
		p.coordBuffer = minify.Number(p.coordBuffer)

		if prevDigit && (p.coordBuffer[0] >= '0' && p.coordBuffer[0] <= '9' || p.coordBuffer[0] == '.' && prevDigitRequiresSpace) {
			b = append(b, ' ')
		}
		prevDigit = true
		prevDigitRequiresSpace = true
		for _, c := range p.coordBuffer {
			if c == '.' || c == 'e' || c == 'E' {
				prevDigitRequiresSpace = false
				break
			}
		}
		b = append(b, p.coordBuffer...)
	}
	return b
}

func toFloat(b []byte) float64 {
	f, err := strconv.ParseFloat(parse.UnsafeToString(b), 64)
	if err != nil {
		panic(err)
	}
	return f
}
<commit_msg>Refactor and bugfixes from fuzz<commit_after>package svg

import (
	"strconv"

	"github.com/tdewolff/minify"
	"github.com/tdewolff/parse"
)

type PathData struct {
	x, y        float64
	coords      [][]byte
	coordFloats []float64

	altBuffer   []byte
	coordBuffer []byte
}

func ShortenPathData(b []byte, p *PathData) []byte {
	var x0, y0 float64
	var cmd byte

	p.x, p.y = 0.0, 0.0
	p.coords = p.coords[:0]
	p.coordFloats = p.coordFloats[:0]

	j := 0
	for i := 0; i < len(b); i++ {
		c := b[i]
		if c == ' ' || c == ',' || c == '\n' || c == '\r' || c == '\t' {
			continue
		} else if c >= 'A' && (cmd == 0 || cmd != c) { // any command
			if cmd != 0 {
				j += p.copyInstruction(b[j:], cmd)
				if cmd == 'M' || cmd == 'm' {
					x0 = p.x
					y0 = p.y
				} else if cmd == 'Z' || cmd == 'z' {
					p.x = x0
					p.y = y0
				}
			}
			cmd = c
			p.coords = p.coords[:0]
			p.coordFloats = p.coordFloats[:0]
		} else if n := parse.Number(b[i:]); n > 0 {
			p.coords = append(p.coords, b[i:i+n])
			p.coordFloats = append(p.coordFloats, toFloat(b[i:i+n]))
			i += n - 1
		}
	}
	j += p.copyInstruction(b[j:], cmd)
	return b[:j]
}

func (p *PathData) copyInstruction(b []byte, cmd byte) int {
	n := len(p.coords)
	isRelativeCmd := cmd >= 'a'

	// get new cursor coordinates
	ax, ay := p.x, p.y
	if n >= 2 && (cmd == 'M' || cmd == 'm' || cmd == 'L' || cmd == 'l' || cmd == 'C' || cmd == 'c' || cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q' || cmd == 'T' || cmd == 't' || cmd == 'A' || cmd == 'a') {
		ax = p.coordFloats[n-2]
		ay = p.coordFloats[n-1]
	} else if n >= 1 && (cmd == 'H' || cmd == 'h' || cmd == 'V' || cmd == 'v') {
		if cmd == 'H' || cmd == 'h' {
			ax = p.coordFloats[n-1]
		} else {
			ay = p.coordFloats[n-1]
		}
	} else if cmd == 'Z' || cmd == 'z' {
		b[0] = 'z'
		return 1
	} else {
		return 0
	}

	// make a current and alternated path with absolute/relative altered
	b = p.shortenCurPosInstruction(b, cmd)
	if isRelativeCmd {
		p.altBuffer = p.shortenAltPosInstruction(p.altBuffer[:0], cmd-'a'+'A', p.x, p.y)
	} else {
		p.altBuffer = p.shortenAltPosInstruction(p.altBuffer[:0], cmd-'A'+'a', -p.x, -p.y)
	}

	// choose shortest, relative or absolute path?
	if len(p.altBuffer) < len(b) {
		copy(b, p.altBuffer)
		b = b[:len(p.altBuffer)]
	}

	// set new cursor coordinates
	if isRelativeCmd {
		p.x += ax
		p.y += ay
	} else {
		p.x = ax
		p.y = ay
	}
	return len(b)
}

func (p *PathData) shortenCurPosInstruction(b []byte, cmd byte) []byte {
	prevDigit := false
	prevDigitRequiresSpace := true

	b[0] = cmd
	j := 1
	for _, coord := range p.coords {
		coord := minify.Number(coord)
		if prevDigit && (coord[0] >= '0' && coord[0] <= '9' || coord[0] == '.' && prevDigitRequiresSpace) {
			b[j] = ' '
			j++
		}
		prevDigit = true
		prevDigitRequiresSpace = true
		for _, c := range coord {
			if c == '.' || c == 'e' || c == 'E' {
				prevDigitRequiresSpace = false
				break
			}
		}
		j += copy(b[j:], coord)
	}
	return b[:j]
}

func (p *PathData) shortenAltPosInstruction(b []byte, cmd byte, dx, dy float64) []byte {
	prevDigit := false
	prevDigitRequiresSpace := true

	b = append(b, cmd)
	for i, f := range p.coordFloats {
		if cmd == 'L' || cmd == 'l' || cmd == 'C' || cmd == 'c' || cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q' || cmd == 'T' || cmd == 't' || cmd == 'M' || cmd == 'm' {
			if i%2 == 0 {
				f += dx
			} else {
				f += dy
			}
		} else if cmd == 'H' || cmd == 'h' {
			f += dx
		} else if cmd == 'V' || cmd == 'v' {
			f += dy
		} else if cmd == 'A' || cmd == 'a' {
			if i%7 == 5 {
				f += dx
			} else if i%7 == 6 {
				f += dy
			}
		} else {
			continue
		}
		p.coordBuffer = strconv.AppendFloat(p.coordBuffer[:0], f, 'f', -1, 32)

		coord := minify.Number(p.coordBuffer)
		if prevDigit && (coord[0] >= '0' && coord[0] <= '9' || coord[0] == '.' && prevDigitRequiresSpace) {
			b = append(b, ' ')
		}
		prevDigit = true
		prevDigitRequiresSpace = true
		for _, c := range coord {
			if c == '.' || c == 'e' || c == 'E' {
				prevDigitRequiresSpace = false
				break
			}
		}
		b = append(b, coord...)
	}
	return b
}

func toFloat(b []byte) float64 {
	f, err := strconv.ParseFloat(string(b), 64)
	if err != nil {
		return 0.0
		//panic(err)
	}
	return f
}
<|endoftext|>


<commit_before>package svg

import (
	strconvStdlib "strconv"

	"github.com/tdewolff/minify"
	"github.com/tdewolff/parse"
	"github.com/tdewolff/strconv"
)

type PathData struct {
	o *Minifier

	x, y        float64
	coords      [][]byte
	coordFloats []float64

	state       PathDataState
	curBuffer   []byte
	altBuffer   []byte
	coordBuffer []byte
}

type PathDataState struct {
	cmd            byte
	prevDigit      bool
	prevDigitIsInt bool
}

func NewPathData(o *Minifier) *PathData {
	return &PathData{o: o}
}

func (p *PathData) ShortenPathData(b []byte) []byte {
	var x0, y0 float64
	var cmd byte

	p.x, p.y = 0.0, 0.0
	p.coords = p.coords[:0]
	p.coordFloats = p.coordFloats[:0]
	p.state = PathDataState{}

	j := 0
	for i := 0; i < len(b); i++ {
		c := b[i]
		if c == ' ' || c == ',' || c == '\n' || c == '\r' || c == '\t' {
			continue
		} else if c >= 'A' && (cmd == 0 || cmd != c || c == 'M' || c == 'm') { // any command
			if cmd != 0 {
				j += p.copyInstruction(b[j:], cmd)
				if cmd == 'M' || cmd == 'm' {
					x0 = p.x
					y0 = p.y
				} else if cmd == 'Z' || cmd == 'z' {
					p.x = x0
					p.y = y0
				}
			}
			cmd = c
			p.coords = p.coords[:0]
			p.coordFloats = p.coordFloats[:0]
		} else if n := parse.Number(b[i:]); n > 0 {
			f, _ := strconv.ParseFloat(b[i : i+n])
			p.coords = append(p.coords, b[i:i+n])
			p.coordFloats = append(p.coordFloats, f)
			i += n - 1
		}
	}
	if cmd != 0 {
		j += p.copyInstruction(b[j:], cmd)
	}
	return b[:j]
}

func (p *PathData) copyInstruction(b []byte, cmd byte) int {
	n := len(p.coords)
	if n == 0 {
		if cmd == 'Z' || cmd == 'z' {
			b[0] = 'z'
			return 1
		}
		return 0
	}
	isRelCmd := cmd >= 'a'

	// get new cursor coordinates
	di := 0
	if (cmd == 'M' || cmd == 'm' || cmd == 'L' || cmd == 'l' || cmd == 'T' || cmd == 't') && n%2 == 0 {
		di = 2
		// reprint M always, as the first pair is a move but subsequent pairs are L
		if cmd == 'M' || cmd == 'm' {
			p.state.cmd = byte(0)
		}
	} else if cmd == 'H' || cmd == 'h' || cmd == 'V' || cmd == 'v' {
		di = 1
	} else if (cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q') && n%4 == 0 {
		di = 4
	} else if (cmd == 'C' || cmd == 'c') && n%6 == 0 {
		di = 6
	} else if (cmd == 'A' || cmd == 'a') && n%7 == 0 {
		di = 7
	} else {
		return 0
	}

	j := 0
	origCmd := cmd
	ax, ay := 0.0, 0.0
	for i := 0; i < n; i += di {
		// subsequent coordinate pairs for M are really L
		if i > 0 && (origCmd == 'M' || origCmd == 'm') {
			origCmd = 'L' + (origCmd - 'M')
		}

		cmd = origCmd
		coords := p.coords[i : i+di]
		coordFloats := p.coordFloats[i : i+di]

		if cmd == 'H' || cmd == 'h' {
			ax = coordFloats[di-1]
			if isRelCmd {
				ay = 0
			} else {
				ay = p.y
			}
		} else if cmd == 'V' || cmd == 'v' {
			if isRelCmd {
				ax = 0
			} else {
				ax = p.x
			}
			ay = coordFloats[di-1]
		} else {
			ax = coordFloats[di-2]
			ay = coordFloats[di-1]
		}

		// switch from L to H or V whenever possible
		if cmd == 'L' || cmd == 'l' {
			if isRelCmd {
				if coordFloats[0] == 0 {
					cmd = 'v'
					coords = coords[1:]
					coordFloats = coordFloats[1:]
				} else if coordFloats[1] == 0 {
					cmd = 'h'
					coords = coords[:1]
					coordFloats = coordFloats[:1]
				}
			} else {
				if coordFloats[0] == p.x {
					cmd = 'V'
					coords = coords[1:]
					coordFloats = coordFloats[1:]
				} else if coordFloats[1] == p.y {
					cmd = 'H'
					coords = coords[:1]
					coordFloats = coordFloats[:1]
				}
			}
		}

		// make a current and alternated path with absolute/relative altered
		var curState, altState PathDataState
		curState = p.shortenCurPosInstruction(cmd, coords)
		if isRelCmd {
			altState = p.shortenAltPosInstruction(cmd-'a'+'A', coordFloats, p.x, p.y)
		} else {
			altState = p.shortenAltPosInstruction(cmd-'A'+'a', coordFloats, -p.x, -p.y)
		}

		// choose shortest, relative or absolute path?
		if len(p.altBuffer) < len(p.curBuffer) {
			j += copy(b[j:], p.altBuffer)
			p.state = altState
		} else {
			j += copy(b[j:], p.curBuffer)
			p.state = curState
		}

		if isRelCmd {
			p.x += ax
			p.y += ay
		} else {
			p.x = ax
			p.y = ay
		}
	}
	return j
}

func (p *PathData) shortenCurPosInstruction(cmd byte, coords [][]byte) PathDataState {
	state := p.state
	p.curBuffer = p.curBuffer[:0]
	if cmd != state.cmd && !(state.cmd == 'M' && cmd == 'L' || state.cmd == 'm' && cmd == 'l') {
		p.curBuffer = append(p.curBuffer, cmd)
		state.cmd = cmd
		state.prevDigit = false
		state.prevDigitIsInt = false
	}
	for _, coord := range coords {
		coord := minify.Number(coord, -1)
		if state.prevDigit && (coord[0] >= '0' && coord[0] <= '9' || coord[0] == '.' && state.prevDigitIsInt) {
			p.curBuffer = append(p.curBuffer, ' ')
		}
		state.prevDigit = true
		state.prevDigitIsInt = true
		for _, c := range coord {
			if c == '.' || c == 'e' || c == 'E' {
				state.prevDigitIsInt = false
				break
			}
		}
		p.curBuffer = append(p.curBuffer, coord...)
	}
	return state
}

func (p *PathData) shortenAltPosInstruction(cmd byte, coordFloats []float64, x, y float64) PathDataState {
	state := p.state
	p.altBuffer = p.altBuffer[:0]
	if cmd != state.cmd && !(state.cmd == 'M' && cmd == 'L' || state.cmd == 'm' && cmd == 'l') {
		p.altBuffer = append(p.altBuffer, cmd)
		state.cmd = cmd
		state.prevDigit = false
		state.prevDigitIsInt = false
	}
	for i, f := range coordFloats {
		if cmd == 'L' || cmd == 'l' || cmd == 'C' || cmd == 'c' || cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q' || cmd == 'T' || cmd == 't' || cmd == 'M' || cmd == 'm' {
			if i%2 == 0 {
				f += x
			} else {
				f += y
			}
		} else if cmd == 'H' || cmd == 'h' {
			f += x
		} else if cmd == 'V' || cmd == 'v' {
			f += y
		} else if cmd == 'A' || cmd == 'a' {
			if i%7 == 5 {
				f += x
			} else if i%7 == 6 {
				f += y
			}
		} else {
			continue
		}

		coord, ok := strconv.AppendFloat(p.coordBuffer[:0], f, p.o.Decimals)
		// if string(coord) != strconvStdlib.FormatFloat(f, 'g', 6, 64) {
		// 	fmt.Println(string(coord), "!=", strconvStdlib.FormatFloat(f, 'g', 6, 64))
		// }
		p.coordBuffer = coord // keep memory
		if !ok {
			p.coordBuffer = strconvStdlib.AppendFloat(p.coordBuffer[:0], f, 'g', p.o.Decimals, 64)
			coord = minify.Number(p.coordBuffer, -1)
		}

		if state.prevDigit && (coord[0] >= '0' && coord[0] <= '9' || coord[0] == '.' && state.prevDigitIsInt) {
			p.altBuffer = append(p.altBuffer, ' ')
		}
		state.prevDigit = true
		state.prevDigitIsInt = true
		for _, c := range coord {
			if c == '.' || c == 'e' || c == 'E' {
				state.prevDigitIsInt = false
				break
			}
		}
		p.altBuffer = append(p.altBuffer, coord...)
	}
	return state
}
<commit_msg>AppendFloat precision breaks tests at the moment<commit_after>package svg

import (
	strconvStdlib "strconv"

	"github.com/tdewolff/minify"
	"github.com/tdewolff/parse"
	"github.com/tdewolff/strconv"
)

type PathData struct {
	o *Minifier

	x, y        float64
	coords      [][]byte
	coordFloats []float64

	state       PathDataState
	curBuffer   []byte
	altBuffer   []byte
	coordBuffer []byte
}

type PathDataState struct {
	cmd            byte
	prevDigit      bool
	prevDigitIsInt bool
}

func NewPathData(o *Minifier) *PathData {
	return &PathData{o: o}
}

func (p *PathData) ShortenPathData(b []byte) []byte {
	var x0, y0 float64
	var cmd byte

	p.x, p.y = 0.0, 0.0
	p.coords = p.coords[:0]
	p.coordFloats = p.coordFloats[:0]
	p.state = PathDataState{}

	j := 0
	for i := 0; i < len(b); i++ {
		c := b[i]
		if c == ' ' || c == ',' || c == '\n' || c == '\r' || c == '\t' {
			continue
		} else if c >= 'A' && (cmd == 0 || cmd != c || c == 'M' || c == 'm') { // any command
			if cmd != 0 {
				j += p.copyInstruction(b[j:], cmd)
				if cmd == 'M' || cmd == 'm' {
					x0 = p.x
					y0 = p.y
				} else if cmd == 'Z' || cmd == 'z' {
					p.x = x0
					p.y = y0
				}
			}
			cmd = c
			p.coords = p.coords[:0]
			p.coordFloats = p.coordFloats[:0]
		} else if n := parse.Number(b[i:]); n > 0 {
			f, _ := strconv.ParseFloat(b[i : i+n])
			p.coords = append(p.coords, b[i:i+n])
			p.coordFloats = append(p.coordFloats, f)
			i += n - 1
		}
	}
	if cmd != 0 {
		j += p.copyInstruction(b[j:], cmd)
	}
	return b[:j]
}

func (p *PathData) copyInstruction(b []byte, cmd byte) int {
	n := len(p.coords)
	if n == 0 {
		if cmd == 'Z' || cmd == 'z' {
			b[0] = 'z'
			return 1
		}
		return 0
	}
	isRelCmd := cmd >= 'a'

	// get new cursor coordinates
	di := 0
	if (cmd == 'M' || cmd == 'm' || cmd == 'L' || cmd == 'l' || cmd == 'T' || cmd == 't') && n%2 == 0 {
		di = 2
		// reprint M always, as the first pair is a move but subsequent pairs are L
		if cmd == 'M' || cmd == 'm' {
			p.state.cmd = byte(0)
		}
	} else if cmd == 'H' || cmd == 'h' || cmd == 'V' || cmd == 'v' {
		di = 1
	} else if (cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q') && n%4 == 0 {
		di = 4
	} else if (cmd == 'C' || cmd == 'c') && n%6 == 0 {
		di = 6
	} else if (cmd == 'A' || cmd == 'a') && n%7 == 0 {
		di = 7
	} else {
		return 0
	}

	j := 0
	origCmd := cmd
	ax, ay := 0.0, 0.0
	for i := 0; i < n; i += di {
		// subsequent coordinate pairs for M are really L
		if i > 0 && (origCmd == 'M' || origCmd == 'm') {
			origCmd = 'L' + (origCmd - 'M')
		}

		cmd = origCmd
		coords := p.coords[i : i+di]
		coordFloats := p.coordFloats[i : i+di]

		if cmd == 'H' || cmd == 'h' {
			ax = coordFloats[di-1]
			if isRelCmd {
				ay = 0
			} else {
				ay = p.y
			}
		} else if cmd == 'V' || cmd == 'v' {
			if isRelCmd {
				ax = 0
			} else {
				ax = p.x
			}
			ay = coordFloats[di-1]
		} else {
			ax = coordFloats[di-2]
			ay = coordFloats[di-1]
		}

		// switch from L to H or V whenever possible
		if cmd == 'L' || cmd == 'l' {
			if isRelCmd {
				if coordFloats[0] == 0 {
					cmd = 'v'
					coords = coords[1:]
					coordFloats = coordFloats[1:]
				} else if coordFloats[1] == 0 {
					cmd = 'h'
					coords = coords[:1]
					coordFloats = coordFloats[:1]
				}
			} else {
				if coordFloats[0] == p.x {
					cmd = 'V'
					coords = coords[1:]
					coordFloats = coordFloats[1:]
				} else if coordFloats[1] == p.y {
					cmd = 'H'
					coords = coords[:1]
					coordFloats = coordFloats[:1]
				}
			}
		}

		// make a current and alternated path with absolute/relative altered
		var curState, altState PathDataState
		curState = p.shortenCurPosInstruction(cmd, coords)
		if isRelCmd {
			altState = p.shortenAltPosInstruction(cmd-'a'+'A', coordFloats, p.x, p.y)
		} else {
			altState = p.shortenAltPosInstruction(cmd-'A'+'a', coordFloats, -p.x, -p.y)
		}

		// choose shortest, relative or absolute path?
		if len(p.altBuffer) < len(p.curBuffer) {
			j += copy(b[j:], p.altBuffer)
			p.state = altState
		} else {
			j += copy(b[j:], p.curBuffer)
			p.state = curState
		}

		if isRelCmd {
			p.x += ax
			p.y += ay
		} else {
			p.x = ax
			p.y = ay
		}
	}
	return j
}

func (p *PathData) shortenCurPosInstruction(cmd byte, coords [][]byte) PathDataState {
	state := p.state
	p.curBuffer = p.curBuffer[:0]
	if cmd != state.cmd && !(state.cmd == 'M' && cmd == 'L' || state.cmd == 'm' && cmd == 'l') {
		p.curBuffer = append(p.curBuffer, cmd)
		state.cmd = cmd
		state.prevDigit = false
		state.prevDigitIsInt = false
	}
	for _, coord := range coords {
		coord := minify.Number(coord, -1)
		if state.prevDigit && (coord[0] >= '0' && coord[0] <= '9' || coord[0] == '.' && state.prevDigitIsInt) {
			p.curBuffer = append(p.curBuffer, ' ')
		}
		state.prevDigit = true
		state.prevDigitIsInt = true
		for _, c := range coord {
			if c == '.' || c == 'e' || c == 'E' {
				state.prevDigitIsInt = false
				break
			}
		}
		p.curBuffer = append(p.curBuffer, coord...)
	}
	return state
}

func (p *PathData) shortenAltPosInstruction(cmd byte, coordFloats []float64, x, y float64) PathDataState {
	state := p.state
	p.altBuffer = p.altBuffer[:0]
	if cmd != state.cmd && !(state.cmd == 'M' && cmd == 'L' || state.cmd == 'm' && cmd == 'l') {
		p.altBuffer = append(p.altBuffer, cmd)
		state.cmd = cmd
		state.prevDigit = false
		state.prevDigitIsInt = false
	}
	for i, f := range coordFloats {
		if cmd == 'L' || cmd == 'l' || cmd == 'C' || cmd == 'c' || cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q' || cmd == 'T' || cmd == 't' || cmd == 'M' || cmd == 'm' {
			if i%2 == 0 {
				f += x
			} else {
				f += y
			}
		} else if cmd == 'H' || cmd == 'h' {
			f += x
		} else if cmd == 'V' || cmd == 'v' {
			f += y
		} else if cmd == 'A' || cmd == 'a' {
			if i%7 == 5 {
				f += x
			} else if i%7 == 6 {
				f += y
			}
		} else {
			continue
		}

		coord, ok := strconv.AppendFloat(p.coordBuffer[:0], f, 6)
		// if string(coord) != strconvStdlib.FormatFloat(f, 'g', 6, 64) {
		// 	fmt.Println(string(coord), "!=", strconvStdlib.FormatFloat(f, 'g', 6, 64))
		// }
		p.coordBuffer = coord // keep memory
		if !ok {
			p.coordBuffer = strconvStdlib.AppendFloat(p.coordBuffer[:0], f, 'g', 6, 64)
			coord = minify.Number(p.coordBuffer, -1)
		}

		if state.prevDigit && (coord[0] >= '0' && coord[0] <= '9' || coord[0] == '.' && state.prevDigitIsInt) {
			p.altBuffer = append(p.altBuffer, ' ')
		}
		state.prevDigit = true
		state.prevDigitIsInt = true
		for _, c := range coord {
			if c == '.' || c == 'e' || c == 'E' {
				state.prevDigitIsInt = false
				break
			}
		}
		p.altBuffer = append(p.altBuffer, coord...)
	}
	return state
}
<|endoftext|>


<commit_before>// Package web Cozy Stack API.
//
// Cozy is a personal platform as a service with a focus on data.
//
// Terms Of Service:
//
// there are no TOS at this moment, use at your own risk we take no responsibility
//
//     Schemes: https
//     Host: localhost
//     BasePath: /
//     Version: 0.0.1
//     License: AGPL-3.0 https://opensource.org/licenses/agpl-3.0
//     Contact: Bruno Michel <bruno@cozycloud.cc> https://cozy.io/
//
//     Consumes:
//     - application/json
//
//     Produces:
//     - application/json
//
// swagger:meta
package web

import (
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/cozy/cozy-stack/web/apps"
	"github.com/cozy/cozy-stack/web/auth"
	"github.com/cozy/cozy-stack/web/data"
	"github.com/cozy/cozy-stack/web/files"
	"github.com/cozy/cozy-stack/web/middlewares"
	"github.com/cozy/cozy-stack/web/status"
	"github.com/cozy/cozy-stack/web/version"
	"github.com/gin-gonic/gin"
)

// SetupRoutes sets the routing for HTTP endpoints to the Go methods
func SetupRoutes(router *gin.Engine) {
	router.Use(middlewares.ParseHost())
	router.Use(middlewares.ServeApp(apps.Serve))
	router.Use(middlewares.ErrorHandler())
	router.Use(corsMiddleware("/apps", "/data", "/files"))

	auth.Routes(router)
	apps.Routes(router.Group("/apps", middlewares.NeedInstance()))
	data.Routes(router.Group("/data", middlewares.NeedInstance()))
	files.Routes(router.Group("/files", middlewares.NeedInstance()))
	status.Routes(router.Group("/status"))
	version.Routes(router.Group("/version"))
}

func corsMiddleware(routes ...string) gin.HandlerFunc {
	normalHeaders := make(http.Header)
	normalHeaders.Set("Access-Control-Allow-Credentials", "true")

	preflightHeaders := make(http.Header)
	preflightHeaders.Set("Access-Control-Allow-Credentials", "true")
	preflightHeaders.Set("Access-Control-Allow-Methods", "*")
	preflightHeaders.Set("Access-Control-Max-Age", strconv.FormatInt(int64(12*time.Hour/time.Second), 10))

	return func(c *gin.Context) {
		origin := c.Request.Header.Get("Origin")

		// TODO(oauth): check that the Origin header matches a subdomain of the
		// instance or a registered domain for an OAuth2 app/device.
		if origin == "" {
			return
		}

		path := c.Request.URL.Path
		valid := false
		for _, route := range routes {
			if strings.HasPrefix(path, route) {
				valid = true
				break
			}
		}

		if !valid {
			c.AbortWithStatus(http.StatusForbidden)
			return
		}

		isOptions := c.Request.Method == "OPTIONS"

		var headers http.Header
		if isOptions {
			headers = preflightHeaders
		} else {
			headers = normalHeaders
		}

		header := c.Writer.Header()
		for key, value := range headers {
			header[key] = value
		}

		c.Header("Access-Control-Allow-Origin", origin)

		if isOptions {
			c.Header("Access-Control-Allow-Headers", c.Request.Header.Get("Access-Control-Request-Headers"))
			c.AbortWithStatus(http.StatusNoContent)
		}
	}
}
<commit_msg>Add NOTE on CORS middleware being "global"<commit_after>// Package web Cozy Stack API.
//
// Cozy is a personal platform as a service with a focus on data.
//
// Terms Of Service:
//
// there are no TOS at this moment, use at your own risk we take no responsibility
//
//     Schemes: https
//     Host: localhost
//     BasePath: /
//     Version: 0.0.1
//     License: AGPL-3.0 https://opensource.org/licenses/agpl-3.0
//     Contact: Bruno Michel <bruno@cozycloud.cc> https://cozy.io/
//
//     Consumes:
//     - application/json
//
//     Produces:
//     - application/json
//
// swagger:meta
package web

import (
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/cozy/cozy-stack/web/apps"
	"github.com/cozy/cozy-stack/web/auth"
	"github.com/cozy/cozy-stack/web/data"
	"github.com/cozy/cozy-stack/web/files"
	"github.com/cozy/cozy-stack/web/middlewares"
	"github.com/cozy/cozy-stack/web/status"
	"github.com/cozy/cozy-stack/web/version"
	"github.com/gin-gonic/gin"
)

// SetupRoutes sets the routing for HTTP endpoints to the Go methods
func SetupRoutes(router *gin.Engine) {
	router.Use(middlewares.ParseHost())
	router.Use(middlewares.ServeApp(apps.Serve))
	router.Use(middlewares.ErrorHandler())

	// NOTE: CORS middleware is a "global" one because of the way gin works: to
	// handle preflight requests with OPTIONS method, every route would have to
	// have an empty OPTIONS handler in order to not get a 404 and actually
	// entering the middleware.
	router.Use(corsMiddleware("/apps", "/data", "/files"))

	auth.Routes(router)
	apps.Routes(router.Group("/apps", middlewares.NeedInstance()))
	data.Routes(router.Group("/data", middlewares.NeedInstance()))
	files.Routes(router.Group("/files", middlewares.NeedInstance()))
	status.Routes(router.Group("/status"))
	version.Routes(router.Group("/version"))
}

func corsMiddleware(routes ...string) gin.HandlerFunc {
	normalHeaders := make(http.Header)
	normalHeaders.Set("Access-Control-Allow-Credentials", "true")

	preflightHeaders := make(http.Header)
	preflightHeaders.Set("Access-Control-Allow-Credentials", "true")
	preflightHeaders.Set("Access-Control-Allow-Methods", "*")
	preflightHeaders.Set("Access-Control-Max-Age", strconv.FormatInt(int64(12*time.Hour/time.Second), 10))

	return func(c *gin.Context) {
		origin := c.Request.Header.Get("Origin")

		// TODO(oauth): check that the Origin header matches a subdomain of the
		// instance or a registered domain for an OAuth2 app/device.
		if origin == "" {
			return
		}

		path := c.Request.URL.Path
		valid := false
		for _, route := range routes {
			if strings.HasPrefix(path, route) {
				valid = true
				break
			}
		}

		if !valid {
			c.AbortWithStatus(http.StatusForbidden)
			return
		}

		isOptions := c.Request.Method == "OPTIONS"

		var headers http.Header
		if isOptions {
			headers = preflightHeaders
		} else {
			headers = normalHeaders
		}

		header := c.Writer.Header()
		for key, value := range headers {
			header[key] = value
		}

		c.Header("Access-Control-Allow-Origin", origin)

		if isOptions {
			c.Header("Access-Control-Allow-Headers", c.Request.Header.Get("Access-Control-Request-Headers"))
			c.AbortWithStatus(http.StatusNoContent)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright © 2013 Jijesh Mohan

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 web

import (
	"code.google.com/p/go.net/websocket"
	"fmt"
	"github.com/ActiveState/tail"
	"github.com/jijeshmohan/logviewer/core"
	"log"
	"net/http"
	"text/template"
)

type MData struct {
	Server string `json:"server"`
	Msg    string `json:"msg"`
}

func (self *MData) String() string {
	return self.Server + " says " + self.Msg
}

type connection struct {
	ws   *websocket.Conn
	send chan *MData
}

type room struct {
	connections map[*connection]bool
	broadcast   chan *MData
	register    chan *connection
	unregister  chan *connection
}

var r = room{
	broadcast:   make(chan *MData),
	register:    make(chan *connection),
	unregister:  make(chan *connection),
	connections: make(map[*connection]bool),
}

func (r *room) run() {
	for {
		select {
		case c := <-r.register:
			r.connections[c] = true
		case c := <-r.unregister:
			delete(r.connections, c)
			close(c.send)
		case m := <-r.broadcast:
			for c := range r.connections {
				select {
				case c.send <- m:
				default:
					delete(r.connections, c)
					close(c.send)
					go c.ws.Close()
				}
			}
		}
	}
}

func (c *connection) reader() {
	for {
		var message MData
		err := websocket.JSON.Receive(c.ws, &message)
		if err != nil {
			break
		}
		// r.broadcast <- message
	}
	c.ws.Close()
}

func (c *connection) writer() {
	for message := range c.send {
		err := websocket.JSON.Send(c.ws, message)
		if err != nil {
			break
		}
	}
	c.ws.Close()
}

var (
	homeTemplate = template.Must(template.ParseFiles("pages/home.html"))
)

func StartServer(port int, config *core.Config) {
	go r.run()
	http.HandleFunc("/", handleHomePage(config))
	http.Handle("/ws", websocket.Handler(wsHandler))
	addr := fmt.Sprintf(":%d", port)
	for _, log := range config.Logs {
		go logFile(log)
	}
	if err := http.ListenAndServe(addr, nil); err != nil {
		log.Fatal("Failed to run server: ", err)
	}
}

func handleHomePage(config *core.Config) func(http.ResponseWriter, *http.Request) {
	return func(c http.ResponseWriter, req *http.Request) {
		data := make(map[string]interface{})
		data["host"] = req.Host
		data["logs"] = config.Logs
		data["server"] = config.ServerName
		homeTemplate.Execute(c, data)
	}
}

func wsHandler(ws *websocket.Conn) {
	c := &connection{send: make(chan *MData, 256), ws: ws}
	r.register <- c
	defer func() { r.unregister <- c }()
	go c.writer()
	c.reader()
}

func logFile(log core.Log) {
	t, _ := tail.TailFile(log.Logpath, tail.Config{Follow: true, ReOpen: true})
	for line := range t.Lines {
		r.broadcast <- &MData{Server: log.Appname, Msg: line.Text}
	}
}
<commit_msg>fixed issue : trying to close channel which is already closed<commit_after>/*
Copyright © 2013 Jijesh Mohan

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 web

import (
	"code.google.com/p/go.net/websocket"
	"fmt"
	"github.com/ActiveState/tail"
	"github.com/jijeshmohan/logviewer/core"
	"log"
	"net/http"
	"text/template"
)

type MData struct {
	Server string `json:"server"`
	Msg    string `json:"msg"`
}

func (self *MData) String() string {
	return self.Server + " says " + self.Msg
}

type connection struct {
	ws   *websocket.Conn
	send chan *MData
}

type room struct {
	connections map[*connection]bool
	broadcast   chan *MData
	register    chan *connection
	unregister  chan *connection
}

var r = room{
	broadcast:   make(chan *MData),
	register:    make(chan *connection),
	unregister:  make(chan *connection),
	connections: make(map[*connection]bool),
}

func (r *room) run() {
	for {
		select {
		case c := <-r.register:
			r.connections[c] = true
		case c := <-r.unregister:
			if _, ok := r.connections[c]; ok {
				delete(r.connections, c)
				close(c.send)
			}
		case m := <-r.broadcast:
			for c := range r.connections {
				select {
				case c.send <- m:
				default:
					delete(r.connections, c)
					close(c.send)
					go c.ws.Close()
				}
			}
		}
	}
}

func (c *connection) reader() {
	for {
		var message MData
		err := websocket.JSON.Receive(c.ws, &message)
		if err != nil {
			break
		}
		// r.broadcast <- message
	}
	c.ws.Close()
}

func (c *connection) writer() {
	for message := range c.send {
		err := websocket.JSON.Send(c.ws, message)
		if err != nil {
			break
		}
	}
	c.ws.Close()
}

var (
	homeTemplate = template.Must(template.ParseFiles("pages/home.html"))
)

func StartServer(port int, config *core.Config) {
	go r.run()
	http.HandleFunc("/", handleHomePage(config))
	http.Handle("/ws", websocket.Handler(wsHandler))
	addr := fmt.Sprintf(":%d", port)
	for _, log := range config.Logs {
		go logFile(log)
	}
	if err := http.ListenAndServe(addr, nil); err != nil {
		log.Fatal("Failed to run server: ", err)
	}
}

func handleHomePage(config *core.Config) func(http.ResponseWriter, *http.Request) {
	return func(c http.ResponseWriter, req *http.Request) {
		data := make(map[string]interface{})
		data["host"] = req.Host
		data["logs"] = config.Logs
		data["server"] = config.ServerName
		homeTemplate.Execute(c, data)
	}
}

func wsHandler(ws *websocket.Conn) {
	c := &connection{send: make(chan *MData, 256), ws: ws}
	r.register <- c
	defer func() { r.unregister <- c }()
	go c.writer()
	c.reader()
}

func logFile(log core.Log) {
	t, _ := tail.TailFile(log.Logpath, tail.Config{Follow: true, ReOpen: true})
	for line := range t.Lines {
		r.broadcast <- &MData{Server: log.Appname, Msg: line.Text}
	}
}
<|endoftext|>


<commit_before>package web

import (
    "encoding/base64"
    "runtime/debug"
    "time"

    "github.com/coocood/freecache"
    identicon "github.com/dgryski/go-identicon"
    "github.com/gin-gonic/gin"
    log "github.com/mgutz/logxi/v1"
)

var Key = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}

type Options struct {
    Logger    log.Logger
    CacheSize int
}

func NewServer(opts Options) *gin.Engine {

    // options
    logger := opts.Logger

    cacheSize := opts.CacheSize * 1024 * 1024
    logger.Info("Creating cache", "size", cacheSize)
    cache := freecache.NewCache(cacheSize)
    debug.SetGCPercent(10)

    // create router
    router := gin.New()
    router.Use(gin.Recovery(), Logger(logger))
    router.GET("/icon/:name", BasicImageRoute(logger))
    router.GET("/encoded/:name", EncodedImageRoute(logger, cache))
    return router
}

func Logger(l log.Logger) gin.HandlerFunc {
    return func(c *gin.Context) {
        // Start timer
        start := time.Now()
        path := c.Request.URL.Path

        // Process request
        c.Next()

        // Stop timer
        end := time.Now()
        latency := end.Sub(start)

        // clientIP := c.ClientIP()
        method := c.Request.Method
        statusCode := c.Writer.Status()
        comment := c.Errors.ByType(gin.ErrorTypePrivate).String()

        l.Info("Request", "method", method, "status", statusCode, "latency", latency, "path", path, "comment", comment)
    }
}

func BasicImageRoute(l log.Logger) gin.HandlerFunc {
    return func(c *gin.Context) {
        icon := identicon.New7x7(Key)
        name := c.Param("name")

        l.Info("Creating identicon", "name", name)

        data := []byte(name)
        pngdata := icon.Render(data)

        c.Writer.Write(pngdata)
        c.Header("Content-Type", "image/png")
    }
}

func EncodedImageRoute(l log.Logger, cache *freecache.Cache) gin.HandlerFunc {
    return func(c *gin.Context) {

        icon := identicon.New7x7(Key)
        name := c.Param("name")
        data := []byte(name)
        if len(data) > 255 {
            c.String(400, "Name too long")
            return
        }

        val, err := cache.Get(data)
        if err != nil || len(val) == 0 {
            l.Info("Encoding identicon", "name", name)
            pngdata := icon.Render(data)
            encoding := base64.StdEncoding.EncodeToString(pngdata)
            val = []byte("data:image/png;base64," + encoding)

            l.Info("Loading cache")
            if err = cache.Set(data, val, 0); err != nil {
                l.Info("Failed to load cache")
            }
        }

        c.Writer.Write(val)
        c.Header("Content-Type", "text/plain")
    }
}
<commit_msg>Add caching to icon route, Add random icon route<commit_after>package web

import (
    "crypto/rand"
    "encoding/base64"
    "runtime/debug"
    "time"

    "github.com/coocood/freecache"
    identicon "github.com/dgryski/go-identicon"
    "github.com/gin-gonic/gin"
    log "github.com/mgutz/logxi/v1"
)

var Key = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}

type Options struct {
    Logger    log.Logger
    CacheSize int
}

func NewServer(opts Options) *gin.Engine {

    // options
    logger := opts.Logger

    cacheSize := opts.CacheSize * 1024 * 1024
    logger.Info("Creating cache", "size", cacheSize)
    cache := freecache.NewCache(cacheSize)
    debug.SetGCPercent(10)

    // create router
    router := gin.New()
    router.Use(gin.Recovery(), Logger(logger))
    router.GET("/icon/:name", BasicImageRoute(logger, cache))
    router.GET("/encoded/:name", EncodedImageRoute(logger, cache))
    router.GET("/random", RandomImageRoute(logger))
    return router
}

func Logger(l log.Logger) gin.HandlerFunc {
    return func(c *gin.Context) {
        // Start timer
        start := time.Now()
        path := c.Request.URL.Path

        // Process request
        c.Next()

        // Stop timer
        end := time.Now()
        latency := end.Sub(start)

        // clientIP := c.ClientIP()
        method := c.Request.Method
        statusCode := c.Writer.Status()
        comment := c.Errors.ByType(gin.ErrorTypePrivate).String()

        l.Info("Request", "method", method, "status", statusCode, "latency", latency, "path", path, "comment", comment)
    }
}

func BasicImageRoute(l log.Logger, cache *freecache.Cache) gin.HandlerFunc {
    return func(c *gin.Context) {
        name := c.Param("name")

        l.Info("Creating identicon", "name", name)

        data := []byte(name)
        if len(data) > 255 {
            c.String(400, "Name too long")
            return
        }

        val, err := cache.Get(data)
        if err != nil || len(val) == 0 {
            icon := identicon.New7x7(Key)

            l.Info("Encoding identicon", "name", name)
            pngdata := icon.Render(data)

            l.Info("Loading cache")
            if err = cache.Set(data, pngdata, 0); err != nil {
                l.Info("Failed to load cache")
            }
            val = pngdata
        }

        c.Writer.Write(val)
        c.Header("Content-Type", "image/png")
    }
}

func EncodedImageRoute(l log.Logger, cache *freecache.Cache) gin.HandlerFunc {
    return func(c *gin.Context) {

        name := c.Param("name")
        data := []byte(name)
        if len(data) > 255 {
            c.String(400, "Name too long")
            return
        }

        val, err := cache.Get(data)
        if err != nil || len(val) == 0 {

            icon := identicon.New7x7(Key)
            l.Info("Encoding identicon", "name", name)
            pngdata := icon.Render(data)

            l.Info("Loading cache")
            if err = cache.Set(data, pngdata, 0); err != nil {
                l.Info("Failed to load cache")
            }

            encoding := base64.StdEncoding.EncodeToString(pngdata)
            val = []byte("data:image/png;base64," + encoding)
        }

        c.Writer.Write(val)
        c.Header("Content-Type", "text/plain")
    }
}

func RandomImageRoute(l log.Logger) gin.HandlerFunc {
    return func(c *gin.Context) {

        data := make([]byte, 16)
        rand.Read(data)

        icon := identicon.New7x7(Key)
        pngdata := icon.Render(data)
        c.Writer.Write(pngdata)
        c.Header("Content-Type", "image/png")
    }
}
<|endoftext|>


<commit_before>package thermal

import (
	"code.google.com/p/go.crypto/nacl/box"
	"code.google.com/p/go.crypto/nacl/secretbox"
	"code.google.com/p/go.crypto/poly1305"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"log"
)

// cs3a is an implementation of the NaCl based cipher set 3a
type cs3a struct {
	id             string
	fingerprintBin []byte
	fingerprintHex string
	publicKey      [32]byte
	privateKey     [32]byte
}

// initialize generates a key pair and sets up the cipher set
func (cs *cs3a) initialize() error {

	// generate the key pair
	publicKey, privateKey, err := box.GenerateKey(rand.Reader)
	if err != nil {
		log.Println("Error generating NaCl keypair in cs3a initialization")
		return err
	}

	// generate the fingerprint hash
	hash256 := sha256.New()
	hash256.Write(publicKey[:])
	fingerprintBin := hash256.Sum(nil)
	fingerprintHex := fmt.Sprintf("%x", fingerprintBin)

	// initialize the struct
	cs.id = "cs3a"
	cs.fingerprintBin = fingerprintBin
	cs.fingerprintHex = fingerprintHex
	cs.publicKey = *publicKey
	cs.privateKey = *privateKey

	return nil

}

func (cs *cs3a) String() string {
	return fmt.Sprintf("%s: %x", cs.id, cs.fingerprint)
}

func (cs *cs3a) csid() string {
	return cs.id
}

// fingerprint returns the csid and fingerprint for use in a 'parts' set
func (cs *cs3a) fingerprint() (string, string) {
	return cs.id, cs.fingerprintHex
}

func (cs *cs3a) encryptOpenPacket(packet []byte, receiverPublicKey *[32]byte) (openPacketBody []byte, lineSharedSecret *[32]byte, err error) {

	// switch key pair
	// cs.publicKey and cs.privateKey should already be populated

	// line key pair
	linePublicKey, linePrivateKey, err := box.GenerateKey(rand.Reader)
	if err != nil {
		log.Println("Error generating NaCl keypair for line")
		return openPacketBody, lineSharedSecret, err
	}

	// Encrypt the inner packet
	var nonce [24]byte
	var encInnerPacket []byte

	box.Precompute(lineSharedSecret, receiverPublicKey, linePrivateKey)
	secretbox.Seal(encInnerPacket, packet, &nonce, lineSharedSecret)

	// Generate the mac and assemble the body for the outer packet
	// <mac><sender-line-public-key><encrypted-inner-packet-data>
	var macKey [32]byte
	var mac [16]byte
	var openPacketData []byte

	box.Precompute(&macKey, receiverPublicKey, &cs.privateKey)
	openPacketData = append(linePublicKey[:], encInnerPacket...)
	poly1305.Sum(&mac, openPacketData, &macKey)
	openPacketBody = append(mac[:], openPacketData...)

	return openPacketBody, lineSharedSecret, nil

}

func (cs *cs3a) decryptOpenPacket(openPacketBody []byte, senderPublicKey *[32]byte) (packet []byte, lineSharedSecret [32]byte, err error) {

	// switch key pair
	// cs.publicKey and cs.privateKey should already be populated

	// Unpack the outer packet body
	// <mac><sender-line-public-key><encrypted-inner-packet-data>
	var mac [16]byte
	var senderLinePublicKey [32]byte
	var encInnerPacket []byte
	var openPacketData []byte

	copy(mac[:], openPacketBody[:16])
	copy(senderLinePublicKey[:], openPacketBody[16:48])
	copy(encInnerPacket[:], openPacketBody[48:])
	openPacketData = append(senderLinePublicKey[:], encInnerPacket...)

	// Verify the mac
	var authenticated bool
	var macKey [32]byte

	box.Precompute(&macKey, senderPublicKey, &cs.privateKey)
	authenticated = poly1305.Verify(&mac, openPacketData, &macKey)
	if !authenticated {
		msg := "Incoming open packet failed MAC authentication"
		log.Println(msg)
		err = fmt.Errorf(msg)
		return packet, lineSharedSecret, err
	}

	// Decrypt the inner packet
	var nonce [24]byte

	box.Precompute(&lineSharedSecret, &senderLinePublicKey, &cs.privateKey)
	secretbox.Open(packet, encInnerPacket, &nonce, &lineSharedSecret)

	return packet, lineSharedSecret, nil
}

// The line encryption key is sha256(line-secret, local-line-id, remote-line-id)
func (cs *cs3a) generateLineEncryptionKey(lineSharedSecret *[32]byte, localLineId, remoteLineId *[16]byte) (key [32]byte) {

	hash256 := sha256.New()
	hash256.Write(lineSharedSecret[:])
	hash256.Write(localLineId[:])
	hash256.Write(remoteLineId[:])
	keyHash := hash256.Sum(nil)

	copy(key[:], keyHash[:])

	return key
}

// The line decryption key is sha256(line-secret, remote-line-id, local-line-id)
func (cs *cs3a) generateLineDecryptionKey(lineSharedSecret *[32]byte, localLineId, remoteLineId *[16]byte) (key [32]byte) {

	hash256 := sha256.New()
	hash256.Write(lineSharedSecret[:])
	hash256.Write(remoteLineId[:])
	hash256.Write(localLineId[:])
	keyBin := hash256.Sum(nil)

	copy(key[:], keyBin[:])

	return key
}

// The cs3a encrypted line packet is <nonce><secretbox>
func (cs *cs3a) encryptLinePacket(packet []byte, lineEncryptionKey *[32]byte) (linePacketBody []byte) {
	var nonce [24]byte
	var cipherText = make([]byte, 0)

	rand.Reader.Read(nonce[:])
	secretbox.Seal(cipherText, packet, &nonce, lineEncryptionKey)

	linePacketBody = append(nonce[:], cipherText...)

	return linePacketBody
}

func (cs *cs3a) decryptLinePacket(linePacketBody []byte, lineDecryptionKey *[32]byte) (packet []byte) {
	return packet
}
<commit_msg>add the line packet decryption<commit_after>package thermal

import (
	"code.google.com/p/go.crypto/nacl/box"
	"code.google.com/p/go.crypto/nacl/secretbox"
	"code.google.com/p/go.crypto/poly1305"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"log"
)

// cs3a is an implementation of the NaCl based cipher set 3a
type cs3a struct {
	id             string
	fingerprintBin []byte
	fingerprintHex string
	publicKey      [32]byte
	privateKey     [32]byte
}

// initialize generates a key pair and sets up the cipher set
func (cs *cs3a) initialize() error {

	// generate the key pair
	publicKey, privateKey, err := box.GenerateKey(rand.Reader)
	if err != nil {
		log.Println("Error generating NaCl keypair in cs3a initialization")
		return err
	}

	// generate the fingerprint hash
	hash256 := sha256.New()
	hash256.Write(publicKey[:])
	fingerprintBin := hash256.Sum(nil)
	fingerprintHex := fmt.Sprintf("%x", fingerprintBin)

	// initialize the struct
	cs.id = "cs3a"
	cs.fingerprintBin = fingerprintBin
	cs.fingerprintHex = fingerprintHex
	cs.publicKey = *publicKey
	cs.privateKey = *privateKey

	return nil

}

func (cs *cs3a) String() string {
	return fmt.Sprintf("%s: %x", cs.id, cs.fingerprint)
}

func (cs *cs3a) csid() string {
	return cs.id
}

// fingerprint returns the csid and fingerprint for use in a 'parts' set
func (cs *cs3a) fingerprint() (string, string) {
	return cs.id, cs.fingerprintHex
}

func (cs *cs3a) encryptOpenPacket(packet []byte, receiverPublicKey *[32]byte) (openPacketBody []byte, lineSharedSecret *[32]byte, err error) {

	// switch key pair
	// cs.publicKey and cs.privateKey should already be populated

	// line key pair
	linePublicKey, linePrivateKey, err := box.GenerateKey(rand.Reader)
	if err != nil {
		log.Println("Error generating NaCl keypair for line")
		return openPacketBody, lineSharedSecret, err
	}

	// Encrypt the inner packet
	var nonce [24]byte
	var encInnerPacket []byte

	box.Precompute(lineSharedSecret, receiverPublicKey, linePrivateKey)
	secretbox.Seal(encInnerPacket, packet, &nonce, lineSharedSecret)

	// Generate the mac and assemble the body for the outer packet
	// <mac><sender-line-public-key><encrypted-inner-packet-data>
	var macKey [32]byte
	var mac [16]byte
	var openPacketData []byte

	box.Precompute(&macKey, receiverPublicKey, &cs.privateKey)
	openPacketData = append(linePublicKey[:], encInnerPacket...)
	poly1305.Sum(&mac, openPacketData, &macKey)
	openPacketBody = append(mac[:], openPacketData...)

	return openPacketBody, lineSharedSecret, nil

}

func (cs *cs3a) decryptOpenPacket(openPacketBody []byte, senderPublicKey *[32]byte) (packet []byte, lineSharedSecret [32]byte, err error) {

	// switch key pair
	// cs.publicKey and cs.privateKey should already be populated

	// Unpack the outer packet body
	// <mac><sender-line-public-key><encrypted-inner-packet-data>
	var mac [16]byte
	var senderLinePublicKey [32]byte
	var encInnerPacket []byte
	var openPacketData []byte

	copy(mac[:], openPacketBody[:16])
	copy(senderLinePublicKey[:], openPacketBody[16:48])
	copy(encInnerPacket[:], openPacketBody[48:])
	openPacketData = append(senderLinePublicKey[:], encInnerPacket...)

	// Verify the mac
	var authenticated bool
	var macKey [32]byte

	box.Precompute(&macKey, senderPublicKey, &cs.privateKey)
	authenticated = poly1305.Verify(&mac, openPacketData, &macKey)
	if !authenticated {
		msg := "Incoming open packet failed MAC authentication"
		log.Println(msg)
		err = fmt.Errorf(msg)
		return packet, lineSharedSecret, err
	}

	// Decrypt the inner packet
	var nonce [24]byte

	box.Precompute(&lineSharedSecret, &senderLinePublicKey, &cs.privateKey)
	secretbox.Open(packet, encInnerPacket, &nonce, &lineSharedSecret)

	return packet, lineSharedSecret, nil
}

// The line encryption key is sha256(line-secret, local-line-id, remote-line-id)
func (cs *cs3a) generateLineEncryptionKey(lineSharedSecret *[32]byte, localLineId, remoteLineId *[16]byte) (key [32]byte) {

	hash256 := sha256.New()
	hash256.Write(lineSharedSecret[:])
	hash256.Write(localLineId[:])
	hash256.Write(remoteLineId[:])
	keyHash := hash256.Sum(nil)

	copy(key[:], keyHash[:])

	return key
}

// The line decryption key is sha256(line-secret, remote-line-id, local-line-id)
func (cs *cs3a) generateLineDecryptionKey(lineSharedSecret *[32]byte, localLineId, remoteLineId *[16]byte) (key [32]byte) {

	hash256 := sha256.New()
	hash256.Write(lineSharedSecret[:])
	hash256.Write(remoteLineId[:])
	hash256.Write(localLineId[:])
	keyBin := hash256.Sum(nil)

	copy(key[:], keyBin[:])

	return key
}

// The cs3a encrypted line packet is <nonce><secretbox>
func (cs *cs3a) encryptLinePacket(packet []byte, lineEncryptionKey *[32]byte) (linePacketBody []byte) {
	var nonce [24]byte
	var cipherText = make([]byte, 0)

	rand.Reader.Read(nonce[:])
	secretbox.Seal(cipherText, packet, &nonce, lineEncryptionKey)

	linePacketBody = append(nonce[:], cipherText...)

	return linePacketBody
}

// The cs3a encrypted line packet is <nonce><secretbox>
func (cs *cs3a) decryptLinePacket(linePacketBody []byte, lineDecryptionKey *[32]byte) (packet []byte) {
	var nonce [24]byte
	copy(nonce[:], linePacketBody[:24])
	linePacketData := linePacketBody[24:]
	secretbox.Open(packet, linePacketData, &nonce, lineDecryptionKey)
	return packet
}
<|endoftext|>


<commit_before>package main

import (
    "os"
    "fmt"
    "bufio"
    "strconv"
    "encoding/json"
)

type command struct {
    Path string `json:"path"`
    Args []string `json:"args"`
    Env map[string]string `json:"env"`
}

func usage() {
    fmt.Fprintf(os.Stderr, "Usage: dasc <req fd> <res fd>\n");
}

func getIntArg(i int) int {
    if i < len(os.Args) {
        a, err := strconv.Atoi(os.Args[i])
        if err == nil {
            return a
        }
    }
    usage()
    os.Exit(1)
    return -1
}

func main() {
    reqfd := uintptr(getIntArg(1))
    resfd := uintptr(getIntArg(2))
    req := os.NewFile(reqfd, "<request pipe>")
    res := bufio.NewReader(os.NewFile(resfd, "<response pipe>"))

    cmd := command{
        "/usr/bin/env",
        []string{"/usr/bin/env"},
        map[string]string{"some_key": "some_value"},
    }
    json, err := json.Marshal(cmd)
    if err != nil {
        panic("failed to marshal command")
    }
    req.Write(json)
    req.WriteString("\n")

    msg, err := res.ReadBytes('\n')
    if err == nil {
        fmt.Printf("response: %s", msg)
    }
}
<commit_msg>dasc.go: very rough (but working!) REPL<commit_after>package main

import (
    "os"
    "fmt"
    "bufio"
    "strconv"
    "strings"
    "encoding/json"
)

type command struct {
    Path string `json:"path"`
    Args []string `json:"args"`
    Env map[string]string `json:"env"`
}

func usage() {
    fmt.Fprintf(os.Stderr, "Usage: dasc <req fd> <res fd>\n");
}

func getIntArg(i int) int {
    if i < len(os.Args) {
        a, err := strconv.Atoi(os.Args[i])
        if err == nil {
            return a
        }
    }
    usage()
    os.Exit(1)
    return -1
}

func prompt() {
    fmt.Print("> ")
}

func lackeol() {
    fmt.Println("\033[7m%\033[m")
}

func search(path string) string {
    if path[0] == '/' {
        return path
    }
    return "/bin/" + path
}

func readline(stdin *bufio.Reader) (line string, err error) {
    line, err = stdin.ReadString('\n')
    if err == nil {
        line = line[:len(line)-1]
    }
    return
}

func main() {
    reqfd := uintptr(getIntArg(1))
    resfd := uintptr(getIntArg(2))
    req := os.NewFile(reqfd, "<request pipe>")
    res := bufio.NewReader(os.NewFile(resfd, "<response pipe>"))

    stdin := bufio.NewReader(os.Stdin)

    for {
        prompt()
        line, err := readline(stdin)
        if err != nil {
            lackeol()
            break
        }
        words := strings.Split(line, " ")
        if len(words) == 0 {
            continue
        }
        words[0] = search(words[0])
        cmd := command{}
        cmd.Path = words[0]
        cmd.Args = words
        cmd.Env = map[string]string{}

        json, err := json.Marshal(cmd)
        if err != nil {
            panic("failed to marshal command")
        }
        req.Write(json)
        req.WriteString("\n")

        msg, err := res.ReadBytes('\n')
        if err == nil {
            fmt.Printf("response: %s", msg)
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>server: insert 7.8k payload<commit_after><|endoftext|>


<commit_before>package mysql

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"gnd.la/config"
	"gnd.la/encoding/codec"
	"gnd.la/orm/driver"
	"gnd.la/orm/driver/sql"
	"gnd.la/util/structs"
	"reflect"
	"time"
)

const placeholders = "?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?"

var (
	mysqlBackend     = &Backend{}
	transformedTypes = []reflect.Type{
		reflect.TypeOf((*time.Time)(nil)),
		reflect.TypeOf((*int64)(nil)),
	}
)

type Backend struct {
	sql.SqlBackend
}

func (b *Backend) Name() string {
	return "mysql"
}

func (b *Backend) Tag() string {
	return b.Name()
}

func (b *Backend) FieldType(typ reflect.Type, t *structs.Tag) (string, error) {
	if c := codec.FromTag(t); c != nil {
		if c.Binary || t.PipeName() != "" {
			return "BLOB", nil
		}
		return "TEXT", nil
	}
	var ft string
	switch typ.Kind() {
	case reflect.Bool:
		ft = "BOOL"
	case reflect.Int8:
		ft = "TINYINT"
	case reflect.Uint8:
		ft = "TINYINT UNSIGNED"
	case reflect.Int16:
		ft = "SMALLINT"
	case reflect.Uint16:
		ft = "SMALLINT UNSIGNED"
	case reflect.Int32:
		ft = "INT"
	case reflect.Uint32:
		ft = "INT UNSIGNED"
	case reflect.Int, reflect.Int64:
		ft = "BIGINT"
	case reflect.Uint, reflect.Uint64:
		ft = "BIGINT UNSIGNED"
	case reflect.Float32:
		ft = "FLOAT"
	case reflect.Float64:
		ft = "DOUBLE"
	case reflect.String:
		if ml, ok := t.IntValue("max_length"); ok {
			ft = fmt.Sprintf("VARCHAR (%d)", ml)
		} else if fl, ok := t.IntValue("length"); ok {
			ft = fmt.Sprintf("CHAR (%d)", fl)
		} else {
			ft = "TEXT"
		}
	case reflect.Slice:
		etyp := typ.Elem()
		if etyp.Kind() == reflect.Uint8 {
			// []byte
			ft = "BLOB"
		}
	case reflect.Struct:
		if typ.Name() == "Time" && typ.PkgPath() == "time" {
			ft = "DATETIME"
		}
	}
	if ft != "" {
		return ft, nil
	}
	return "", fmt.Errorf("can't map field type %v to a database type", typ)
}

func (b *Backend) FieldOptions(typ reflect.Type, t *structs.Tag) ([]string, error) {
	var opts []string
	if t.Has("notnull") {
		opts = append(opts, "NOT NULL")
	}
	if t.Has("primary_key") {
		opts = append(opts, "PRIMARY KEY")
	} else if t.Has("unique") {
		opts = append(opts, "UNIQUE")
	}
	if t.Has("auto_increment") {
		opts = append(opts, "AUTO_INCREMENT")
	}
	if def := t.Value("default"); def != "" {
		if typ.Kind() == reflect.String {
			def = "\"" + def + "\""
		}
		opts = append(opts, fmt.Sprintf("DEFAULT %s", def))
	}
	return opts, nil
}

func (b *Backend) Transforms() []reflect.Type {
	return transformedTypes
}

func (b *Backend) ScanInt(val int64, goVal *reflect.Value, t *structs.Tag) error {
	goVal.SetInt(val)
	return nil
}

func (b *Backend) ScanByteSlice(val []byte, goVal *reflect.Value, t *structs.Tag) error {
	return nil
}

func (b *Backend) ScanTime(val *time.Time, goVal *reflect.Value, t *structs.Tag) error {
	goVal.Set(reflect.ValueOf(val.UTC()))
	return nil
}

func (b *Backend) TransformOutValue(val reflect.Value) (interface{}, error) {
	i := val.Interface()
	if t, ok := i.(time.Time); ok {
		return t.UTC(), nil
	}
	return i, nil
}

func mysqlOpener(url *config.URL) (driver.Driver, error) {
	url.Value += "?charset=UTF8&sql_mode=ANSI&parseTime=true&loc=UTC"
	return sql.NewDriver(mysqlBackend, url)
}

func init() {
	driver.Register("mysql", mysqlOpener)
}
<commit_msg>Fix issues with integer scanning in MySQL<commit_after>package mysql

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"gnd.la/config"
	"gnd.la/encoding/codec"
	"gnd.la/orm/driver"
	"gnd.la/orm/driver/sql"
	"gnd.la/util/structs"
	"gnd.la/util/types"
	"reflect"
	"strconv"
	"time"
)

const placeholders = "?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?"

var (
	mysqlBackend     = &Backend{}
	transformedTypes = []reflect.Type{
		reflect.TypeOf((*time.Time)(nil)),
		reflect.TypeOf((*int64)(nil)),
	}
)

type Backend struct {
	sql.SqlBackend
}

func (b *Backend) Name() string {
	return "mysql"
}

func (b *Backend) Tag() string {
	return b.Name()
}

func (b *Backend) FieldType(typ reflect.Type, t *structs.Tag) (string, error) {
	if c := codec.FromTag(t); c != nil {
		if c.Binary || t.PipeName() != "" {
			return "BLOB", nil
		}
		return "TEXT", nil
	}
	var ft string
	switch typ.Kind() {
	case reflect.Bool:
		ft = "BOOL"
	case reflect.Int8:
		ft = "TINYINT"
	case reflect.Uint8:
		ft = "TINYINT UNSIGNED"
	case reflect.Int16:
		ft = "SMALLINT"
	case reflect.Uint16:
		ft = "SMALLINT UNSIGNED"
	case reflect.Int32:
		ft = "INT"
	case reflect.Uint32:
		ft = "INT UNSIGNED"
	case reflect.Int, reflect.Int64:
		ft = "BIGINT"
	case reflect.Uint, reflect.Uint64:
		ft = "BIGINT UNSIGNED"
	case reflect.Float32:
		ft = "FLOAT"
	case reflect.Float64:
		ft = "DOUBLE"
	case reflect.String:
		if ml, ok := t.IntValue("max_length"); ok {
			ft = fmt.Sprintf("VARCHAR (%d)", ml)
		} else if fl, ok := t.IntValue("length"); ok {
			ft = fmt.Sprintf("CHAR (%d)", fl)
		} else {
			ft = "TEXT"
		}
	case reflect.Slice:
		etyp := typ.Elem()
		if etyp.Kind() == reflect.Uint8 {
			// []byte
			ft = "BLOB"
		}
	case reflect.Struct:
		if typ.Name() == "Time" && typ.PkgPath() == "time" {
			ft = "DATETIME"
		}
	}
	if ft != "" {
		return ft, nil
	}
	return "", fmt.Errorf("can't map field type %v to a database type", typ)
}

func (b *Backend) FieldOptions(typ reflect.Type, t *structs.Tag) ([]string, error) {
	var opts []string
	if t.Has("notnull") {
		opts = append(opts, "NOT NULL")
	}
	if t.Has("primary_key") {
		opts = append(opts, "PRIMARY KEY")
	} else if t.Has("unique") {
		opts = append(opts, "UNIQUE")
	}
	if t.Has("auto_increment") {
		opts = append(opts, "AUTO_INCREMENT")
	}
	if def := t.Value("default"); def != "" {
		if typ.Kind() == reflect.String {
			def = "\"" + def + "\""
		}
		opts = append(opts, fmt.Sprintf("DEFAULT %s", def))
	}
	return opts, nil
}

func (b *Backend) Transforms() []reflect.Type {
	return transformedTypes
}

func (b *Backend) ScanInt(val int64, goVal *reflect.Value, t *structs.Tag) error {
	goVal.SetInt(val)
	return nil
}

func (b *Backend) ScanByteSlice(val []byte, goVal *reflect.Value, t *structs.Tag) error {
	// mysql returns u?int types as []byte under
	// some circumstances (not sure exactly when, but other
	// times they're returned as an int64).
	s := string(val)
	typ := goVal.Type()
	switch {
	case types.IsInt(typ):
		v, err := strconv.ParseInt(s, 10, 64)
		if err != nil {
			return err
		}
		goVal.SetInt(v)
	case types.IsUint(typ):
		v, err := strconv.ParseInt(s, 10, 64)
		if err != nil {
			return err
		}
		goVal.SetInt(v)
	default:
		return fmt.Errorf("unexpected type in ScanByteSlice()")
	}
	return nil
}

func (b *Backend) ScanTime(val *time.Time, goVal *reflect.Value, t *structs.Tag) error {
	goVal.Set(reflect.ValueOf(val.UTC()))
	return nil
}

func (b *Backend) TransformOutValue(val reflect.Value) (interface{}, error) {
	i := val.Interface()
	if t, ok := i.(time.Time); ok {
		return t.UTC(), nil
	}
	return i, nil
}

func mysqlOpener(url *config.URL) (driver.Driver, error) {
	url.Value += "?charset=UTF8&sql_mode=ANSI&parseTime=true&loc=UTC"
	return sql.NewDriver(mysqlBackend, url)
}

func init() {
	driver.Register("mysql", mysqlOpener)
}
<|endoftext|>


<commit_before>package api

import (
    "fmt"
    "net/url"
    "strconv"
    "github.com/mitchellh/mapstructure"
)

const (
    DEFAULT_PRODUCT_API_LENGTH = 20
    DEFAULT_PRODUCT_MAX_LENGTH = 100

    DEFAULT_PRODUCT_MAX_OFFSET = 50000
)

type ProductService struct {
    ApiId        string `mapstructure:"api_id"`
    AffiliateId  string `mapstructure:"affiliate_id"`
    Site         string `mapstructure:"site"`
    Service      string `mapstructure:"service"`
    Floor        string `mapstructure:"floor"`
    Length       int64  `mapstructure:"hits"`
    Offset       int64  `mapstructure:"offset"`
    Sort         string `mapstructure:"sort"`
    Keyword      string `mapstructure:"keyword"`
}

type ProductRawResponse struct {
    Request ProductService  `mapstructure:"request"`
    Result  ProductResponse `mapstructure:"result"`
}

type ProductResponse struct {
    ResultCount   int64  `mapstructure:"result_count"`
    TotalCount    int64  `mapstructure:"total_count"`
    FirstPosition int64  `mapstructure:"first_position"`
    Items         []Item `mapstructure:"items"`
}

type Item struct {
    AffiliateUrl       string             `mapstructure:"affiliateURL"`
    AffiliateUrlMobile string             `mapstructure:"affiliateURLsp"`
    CategoryName       string             `mapstructure:"category_name"`
    Comment            string             `mapstructure:"comment"`
    ContentId          string             `mapstructure:"content_id"`
    Date               string             `mapstructure:"date"`
    FloorName          string             `mapstructure:"floor_name"`
    FloorCode          string             `mapstructure:"floor_code"`
    ISBN               string             `mapstructure:"isbn"`
    JANCode            string             `mapstructure:"jancode"`
    ProductCode        string             `mapstructure:"maker_product"`
    ProductId          string             `mapstructure:"product_id"`
    ServiceName        string             `mapstructure:"service_name"`
    ServiceCode        string             `mapstructure:"service_code"`
    Stock              string             `mapstructure:"stock"`
    Title              string             `mapstructure:"title"`
    Url                string             `mapstructure:"URL"`
    UrlMoble           string             `mapstructure:"URLsp"`
    Volume             string             `mapstructure:"volume"`
    ImageUrl           ImageUrlList       `mapstructure:"imageURL"`
    SampleImageUrl     SampleImageUrlList `mapstructure:"sampleImageURL"`
    SampleMovieUrl     SampleMovieUrlList `mapstructure:"sampleMovieURL"`
    Review             ReviewInformation  `mapstructure:"review"`
    PriceInformation   PriceInformation   `mapstructure:"prices"`
    ItemInformation    ItemInformation    `mapstructure:"iteminfo"`
    BandaiInformation  BandaiInformation  `mapstructure:"bandaiinfo"`
    CdInformation      CdInformation      `mapstructure:"cdinfo"`
}

type ImageUrlList struct {
    List  string `mapstructure:"list"`
    Small string `mapstructure:"small"`
    Large string `mapstructure:"large"`
}

type SampleImageUrlList struct {
    Sample_s SmallSampleList  `mapstructure:"sample_s"`
}

type SmallSampleList struct {
    Image []string `mapstructure:"image"`
}

type SampleMovieUrlList struct {
    Size_476_306 string `mapstructure:"size_476_306"`
    Size_560_360 string `mapstructure:"size_560_360"`
    Size_644_414 string `mapstructure:"size_644_414"`
    Size_720_480 string `mapstructure:"size_720_480"`
    PC_flag      bool   `mapstructure:"pc_flag"`
    SP_flag      bool   `mapstructure:"sp_flag"`
}

type PriceInformation struct {
    Price       string             `mapstructure:"price"`
    PriceAll    string             `mapstructure:"price_all"`
    RetailPrice string             `mapstructure:"list_price"`
    Distributions DistributionList `mapstructure:"deliveries"`
}

type DistributionList struct {
    Distribution []Distribution `mapstructure:"delivery"`
}

type Distribution struct {
    Type  string `mapstructure:"type"`
    Price string `mapstructure:"price"`
}

type ItemInformation struct {
    Maker     []ItemComponent `mapstructure:"maker"`
    Label     []ItemComponent `mapstructure:"label"`
    Series    []ItemComponent `mapstructure:"series"`
    Keywords  []ItemComponent `mapstructure:"keyword"`
    Genres    []ItemComponent `mapstructure:"genre"`
    Actors    []ItemComponent `mapstructure:"actor"`
    Artists   []ItemComponent `mapstructure:"artist"`
    Authors   []ItemComponent `mapstructure:"author"`
    Directors []ItemComponent `mapstructure:"director"`
    Fighters  []ItemComponent `mapstructure:"fighter"`
    Colors    []ItemComponent `mapstructure:"color"`
    Sizes     []ItemComponent `mapstructure:"size"`
}

type ItemComponent struct {
    Id   string `mapstructure:"id"`
    Name string `mapstructure:"name"`
}

type BandaiInformation struct {
    TitleCode string `mapstructure:"titlecode"`
}

type CdInformation struct {
    Kind string `mapstructure:"kind"`
}

type ReviewInformation struct {
    Count   int64   `mapstructure:"count"`
    Average float64 `mapstructure:"average"`
}

// NewProductService returns a new service for the given affiliate ID and API ID.
// NewProductServiceは渡したアフィリエイトIDとAPI IDを使用して新しい serviceを返します。
func NewProductService(affiliateId, apiId string) *ProductService {
    return &ProductService{
        ApiId:       apiId,
        AffiliateId: affiliateId,
        Site:        "",
        Service:     "",
        Floor:       "",
        Length:      DEFAULT_PRODUCT_API_LENGTH,
        Offset:      DEFAULT_API_OFFSET,
        Sort:        "",
        Keyword:     "",
    }
}

// Execute requests a url is created by BuildRequestUrl.
// Use ExecuteWeak If you want get this response in interface{}.
//
// BuildRequestUrlで生成したURLにリクエストします
// もし interface{} でこのレスポンスを取得したい場合は ExecuteWeak を使用してください
func (srv *ProductService) Execute() (*ProductResponse, error) {
    result, err := srv.ExecuteWeak()
    if err != nil {
        return nil, err
    }
    var raw ProductRawResponse
    if err = mapstructure.WeakDecode(result, &raw); err != nil {
        return nil, err
    }
    return &raw.Result, nil
}

ExecuteWeak requests a url is created by BuildRequestUrl.
func (srv *ProductService) ExecuteWeak() (interface{}, error) {
    reqUrl, err := srv.BuildRequestUrl()
    if err != nil {
        return nil, err
    }

    return RequestJson(reqUrl)
}

// SetLength set the specified argument to ProductService.Length
// SetLengthはLengthパラメータを設定します
func (srv *ProductService) SetLength(length int64) *ProductService {
    srv.Length = length
    return srv
}

// SetHits set the specified argument to ProductService.Length
// SetHits is the alias for SetLength
//
// SetHitsはLengthパラメータを設定します
func (srv *ProductService) SetHits(length int64) *ProductService {
    srv.SetLength(length)
    return srv
}

// SetOffset set the specified argument to ProductService.Offset
// SetOffsetはOffsetパラメータを設定します
func (srv *ProductService) SetOffset(offset int64) *ProductService {
    srv.Offset = offset
    return srv
}

// SetKeyword set the specified argument to ProductService.Keyword
// SetKeywordはKeywordパラメータを設定します
func (srv *ProductService) SetKeyword(keyword string) *ProductService {
    srv.Keyword = TrimString(keyword)
    return srv
}

// SetSort set the specified argument to ProductService.Sort
// SetSortはSortパラメータを設定します
func (srv *ProductService) SetSort(sort string) *ProductService {
    srv.Sort = TrimString(sort)
    return srv
}

// SetSite set the specified argument to ProductService.Site
// SetSiteはSiteパラメータを設定します
func (srv *ProductService) SetSite(site string) *ProductService {
    srv.Site = TrimString(site)
    return srv
}

// SetService set the specified argument to ProductService.Service
// SetServiceはServiceパラメータを設定します
func (srv *ProductService) SetService(service string) *ProductService {
    srv.Service = TrimString(service)
    return srv
}

// SetFloor set the specified argument to ProductService.Floor
// SetFloorはFloorパラメータを設定します
func (srv *ProductService) SetFloor(floor string) *ProductService {
    srv.Floor = TrimString(floor)
    return srv
}

// ValidateLength validates ProductService.Length within the range (1 <= value <= 100).
// refer to ValidateRange for more information about the range to validate.
//
// ValidateLengthはProductService.Lengthが範囲内(1 <= value <= 100)にあるか検証します。
// 検証範囲について更に詳しく知りたい方はValidateRangeを参照してください
func (srv *ProductService) ValidateLength() bool {
    return ValidateRange(srv.Length, 1, DEFAULT_PRODUCT_MAX_LENGTH)
}

func (srv *ProductService) ValidateOffset() bool {
    return ValidateRange(srv.Offset, 1, DEFAULT_PRODUCT_MAX_OFFSET)
}

// BuildRequestUrl creates url to request product API.
// BuildRequestUrlは商品検索APIにリクエストするためのURLを作成します。
func (srv *ProductService) BuildRequestUrl() (string, error) {
    if srv.ApiId == "" {
        return "", fmt.Errorf("set invalid ApiId parameter.")
    }
    if !ValidateAffiliateId(srv.AffiliateId) {
        return "", fmt.Errorf("set invalid AffiliateId parameter.")
    }

    if !ValidateSite(srv.Site) {
        return "", fmt.Errorf("set invalid Site parameter.")
    }

    queries := url.Values{}
    queries.Set("api_id", srv.ApiId)
    queries.Set("affiliate_id", srv.AffiliateId)
    queries.Set("site", srv.Site)

    if srv.Length != 0 {
        if !srv.ValidateLength() {
            return "", fmt.Errorf("length out of range: %d", srv.Length)
        }
        queries.Set("hits", strconv.FormatInt(srv.Length, 10))
    }

    if srv.Offset != 0 {
        if !srv.ValidateOffset() {
            return "", fmt.Errorf("offset out of range: %d", srv.Offset)
        }
        queries.Set("offset", strconv.FormatInt(srv.Offset, 10))
    }

    if (srv.Service != "") {
        queries.Set("service", srv.Service)
    }
    if (srv.Floor != "") {
        queries.Set("floor", srv.Floor)
    }
    if (srv.Sort != "") {
        queries.Set("sort", srv.Sort)
    }
    if (srv.Keyword != "") {
        queries.Set("keyword", srv.Keyword)
    }
    return API_BASE_URL + "/ItemList?" + queries.Encode(), nil
}<commit_msg>fix block comment<commit_after>package api

import (
    "fmt"
    "net/url"
    "strconv"
    "github.com/mitchellh/mapstructure"
)

const (
    DEFAULT_PRODUCT_API_LENGTH = 20
    DEFAULT_PRODUCT_MAX_LENGTH = 100

    DEFAULT_PRODUCT_MAX_OFFSET = 50000
)

type ProductService struct {
    ApiId        string `mapstructure:"api_id"`
    AffiliateId  string `mapstructure:"affiliate_id"`
    Site         string `mapstructure:"site"`
    Service      string `mapstructure:"service"`
    Floor        string `mapstructure:"floor"`
    Length       int64  `mapstructure:"hits"`
    Offset       int64  `mapstructure:"offset"`
    Sort         string `mapstructure:"sort"`
    Keyword      string `mapstructure:"keyword"`
}

type ProductRawResponse struct {
    Request ProductService  `mapstructure:"request"`
    Result  ProductResponse `mapstructure:"result"`
}

type ProductResponse struct {
    ResultCount   int64  `mapstructure:"result_count"`
    TotalCount    int64  `mapstructure:"total_count"`
    FirstPosition int64  `mapstructure:"first_position"`
    Items         []Item `mapstructure:"items"`
}

type Item struct {
    AffiliateUrl       string             `mapstructure:"affiliateURL"`
    AffiliateUrlMobile string             `mapstructure:"affiliateURLsp"`
    CategoryName       string             `mapstructure:"category_name"`
    Comment            string             `mapstructure:"comment"`
    ContentId          string             `mapstructure:"content_id"`
    Date               string             `mapstructure:"date"`
    FloorName          string             `mapstructure:"floor_name"`
    FloorCode          string             `mapstructure:"floor_code"`
    ISBN               string             `mapstructure:"isbn"`
    JANCode            string             `mapstructure:"jancode"`
    ProductCode        string             `mapstructure:"maker_product"`
    ProductId          string             `mapstructure:"product_id"`
    ServiceName        string             `mapstructure:"service_name"`
    ServiceCode        string             `mapstructure:"service_code"`
    Stock              string             `mapstructure:"stock"`
    Title              string             `mapstructure:"title"`
    Url                string             `mapstructure:"URL"`
    UrlMoble           string             `mapstructure:"URLsp"`
    Volume             string             `mapstructure:"volume"`
    ImageUrl           ImageUrlList       `mapstructure:"imageURL"`
    SampleImageUrl     SampleImageUrlList `mapstructure:"sampleImageURL"`
    SampleMovieUrl     SampleMovieUrlList `mapstructure:"sampleMovieURL"`
    Review             ReviewInformation  `mapstructure:"review"`
    PriceInformation   PriceInformation   `mapstructure:"prices"`
    ItemInformation    ItemInformation    `mapstructure:"iteminfo"`
    BandaiInformation  BandaiInformation  `mapstructure:"bandaiinfo"`
    CdInformation      CdInformation      `mapstructure:"cdinfo"`
}

type ImageUrlList struct {
    List  string `mapstructure:"list"`
    Small string `mapstructure:"small"`
    Large string `mapstructure:"large"`
}

type SampleImageUrlList struct {
    Sample_s SmallSampleList  `mapstructure:"sample_s"`
}

type SmallSampleList struct {
    Image []string `mapstructure:"image"`
}

type SampleMovieUrlList struct {
    Size_476_306 string `mapstructure:"size_476_306"`
    Size_560_360 string `mapstructure:"size_560_360"`
    Size_644_414 string `mapstructure:"size_644_414"`
    Size_720_480 string `mapstructure:"size_720_480"`
    PC_flag      bool   `mapstructure:"pc_flag"`
    SP_flag      bool   `mapstructure:"sp_flag"`
}

type PriceInformation struct {
    Price       string             `mapstructure:"price"`
    PriceAll    string             `mapstructure:"price_all"`
    RetailPrice string             `mapstructure:"list_price"`
    Distributions DistributionList `mapstructure:"deliveries"`
}

type DistributionList struct {
    Distribution []Distribution `mapstructure:"delivery"`
}

type Distribution struct {
    Type  string `mapstructure:"type"`
    Price string `mapstructure:"price"`
}

type ItemInformation struct {
    Maker     []ItemComponent `mapstructure:"maker"`
    Label     []ItemComponent `mapstructure:"label"`
    Series    []ItemComponent `mapstructure:"series"`
    Keywords  []ItemComponent `mapstructure:"keyword"`
    Genres    []ItemComponent `mapstructure:"genre"`
    Actors    []ItemComponent `mapstructure:"actor"`
    Artists   []ItemComponent `mapstructure:"artist"`
    Authors   []ItemComponent `mapstructure:"author"`
    Directors []ItemComponent `mapstructure:"director"`
    Fighters  []ItemComponent `mapstructure:"fighter"`
    Colors    []ItemComponent `mapstructure:"color"`
    Sizes     []ItemComponent `mapstructure:"size"`
}

type ItemComponent struct {
    Id   string `mapstructure:"id"`
    Name string `mapstructure:"name"`
}

type BandaiInformation struct {
    TitleCode string `mapstructure:"titlecode"`
}

type CdInformation struct {
    Kind string `mapstructure:"kind"`
}

type ReviewInformation struct {
    Count   int64   `mapstructure:"count"`
    Average float64 `mapstructure:"average"`
}

// NewProductService returns a new service for the given affiliate ID and API ID.
// NewProductServiceは渡したアフィリエイトIDとAPI IDを使用して新しい serviceを返します。
func NewProductService(affiliateId, apiId string) *ProductService {
    return &ProductService{
        ApiId:       apiId,
        AffiliateId: affiliateId,
        Site:        "",
        Service:     "",
        Floor:       "",
        Length:      DEFAULT_PRODUCT_API_LENGTH,
        Offset:      DEFAULT_API_OFFSET,
        Sort:        "",
        Keyword:     "",
    }
}

// Execute requests a url is created by BuildRequestUrl.
// Use ExecuteWeak If you want get this response in interface{}.
//
// BuildRequestUrlで生成したURLにリクエストします
// もし interface{} でこのレスポンスを取得したい場合は ExecuteWeak を使用してください
func (srv *ProductService) Execute() (*ProductResponse, error) {
    result, err := srv.ExecuteWeak()
    if err != nil {
        return nil, err
    }
    var raw ProductRawResponse
    if err = mapstructure.WeakDecode(result, &raw); err != nil {
        return nil, err
    }
    return &raw.Result, nil
}

// ExecuteWeak requests a url is created by BuildRequestUrl.
// BuildRequestUrlで生成したURLにリクエストします
func (srv *ProductService) ExecuteWeak() (interface{}, error) {
    reqUrl, err := srv.BuildRequestUrl()
    if err != nil {
        return nil, err
    }

    return RequestJson(reqUrl)
}

// SetLength set the specified argument to ProductService.Length
// SetLengthはLengthパラメータを設定します
func (srv *ProductService) SetLength(length int64) *ProductService {
    srv.Length = length
    return srv
}

// SetHits set the specified argument to ProductService.Length
// SetHits is the alias for SetLength
//
// SetHitsはLengthパラメータを設定します
func (srv *ProductService) SetHits(length int64) *ProductService {
    srv.SetLength(length)
    return srv
}

// SetOffset set the specified argument to ProductService.Offset
// SetOffsetはOffsetパラメータを設定します
func (srv *ProductService) SetOffset(offset int64) *ProductService {
    srv.Offset = offset
    return srv
}

// SetKeyword set the specified argument to ProductService.Keyword
// SetKeywordはKeywordパラメータを設定します
func (srv *ProductService) SetKeyword(keyword string) *ProductService {
    srv.Keyword = TrimString(keyword)
    return srv
}

// SetSort set the specified argument to ProductService.Sort
// SetSortはSortパラメータを設定します
func (srv *ProductService) SetSort(sort string) *ProductService {
    srv.Sort = TrimString(sort)
    return srv
}

// SetSite set the specified argument to ProductService.Site
// SetSiteはSiteパラメータを設定します
func (srv *ProductService) SetSite(site string) *ProductService {
    srv.Site = TrimString(site)
    return srv
}

// SetService set the specified argument to ProductService.Service
// SetServiceはServiceパラメータを設定します
func (srv *ProductService) SetService(service string) *ProductService {
    srv.Service = TrimString(service)
    return srv
}

// SetFloor set the specified argument to ProductService.Floor
// SetFloorはFloorパラメータを設定します
func (srv *ProductService) SetFloor(floor string) *ProductService {
    srv.Floor = TrimString(floor)
    return srv
}

// ValidateLength validates ProductService.Length within the range (1 <= value <= 100).
// refer to ValidateRange for more information about the range to validate.
//
// ValidateLengthはProductService.Lengthが範囲内(1 <= value <= 100)にあるか検証します。
// 検証範囲について更に詳しく知りたい方はValidateRangeを参照してください
func (srv *ProductService) ValidateLength() bool {
    return ValidateRange(srv.Length, 1, DEFAULT_PRODUCT_MAX_LENGTH)
}

func (srv *ProductService) ValidateOffset() bool {
    return ValidateRange(srv.Offset, 1, DEFAULT_PRODUCT_MAX_OFFSET)
}

// BuildRequestUrl creates url to request product API.
// BuildRequestUrlは商品検索APIにリクエストするためのURLを作成します。
func (srv *ProductService) BuildRequestUrl() (string, error) {
    if srv.ApiId == "" {
        return "", fmt.Errorf("set invalid ApiId parameter.")
    }
    if !ValidateAffiliateId(srv.AffiliateId) {
        return "", fmt.Errorf("set invalid AffiliateId parameter.")
    }

    if !ValidateSite(srv.Site) {
        return "", fmt.Errorf("set invalid Site parameter.")
    }

    queries := url.Values{}
    queries.Set("api_id", srv.ApiId)
    queries.Set("affiliate_id", srv.AffiliateId)
    queries.Set("site", srv.Site)

    if srv.Length != 0 {
        if !srv.ValidateLength() {
            return "", fmt.Errorf("length out of range: %d", srv.Length)
        }
        queries.Set("hits", strconv.FormatInt(srv.Length, 10))
    }

    if srv.Offset != 0 {
        if !srv.ValidateOffset() {
            return "", fmt.Errorf("offset out of range: %d", srv.Offset)
        }
        queries.Set("offset", strconv.FormatInt(srv.Offset, 10))
    }

    if (srv.Service != "") {
        queries.Set("service", srv.Service)
    }
    if (srv.Floor != "") {
        queries.Set("floor", srv.Floor)
    }
    if (srv.Sort != "") {
        queries.Set("sort", srv.Sort)
    }
    if (srv.Keyword != "") {
        queries.Set("keyword", srv.Keyword)
    }
    return API_BASE_URL + "/ItemList?" + queries.Encode(), nil
}<|endoftext|>


<commit_before>package vault

import (
	"errors"
	"fmt"
	"net/url"
	"time"

	"code.cloudfoundry.org/lager"

	"github.com/cloudfoundry/bosh-cli/director/template"
	"github.com/concourse/atc/creds"
	vaultapi "github.com/hashicorp/vault/api"
)

type VaultManager struct {
	URL string `long:"url" description:"Vault server address used to access secrets."`

	PathPrefix string `long:"path-prefix" default:"/concourse" description:"Path under which to namespace credential lookup."`

	Cache    bool          `bool:"cache" default:"false" description:"Cache returned secrets for their lease duration in memory"`
	MaxLease time.Duration `long:"max-lease" description:"If the cache is enabled, and this is set, override secrets lease duration with a maximum value"`

	TLS struct {
		CACert     string `long:"ca-cert"              description:"Path to a PEM-encoded CA cert file to use to verify the vault server SSL cert."`
		CAPath     string `long:"ca-path"              description:"Path to a directory of PEM-encoded CA cert files to verify the vault server SSL cert."`
		ClientCert string `long:"client-cert"          description:"Path to the client certificate for Vault authorization."`
		ClientKey  string `long:"client-key"           description:"Path to the client private key for Vault authorization."`
		ServerName string `long:"server-name"          description:"If set, is used to set the SNI host when connecting via TLS."`
		Insecure   bool   `long:"insecure-skip-verify" description:"Enable insecure SSL verification."`
	}

	Auth AuthConfig
}

type AuthConfig struct {
	ClientToken string `long:"client-token" description:"Client token for accessing secrets within the Vault server."`

	Backend       string        `long:"auth-backend"               description:"Auth backend to use for logging in to Vault."`
	BackendMaxTTL time.Duration `long:"auth-backend-max-ttl"       description:"Time after which to force a re-login. If not set, the token will just be continuously renewed."`
	RetryMax      time.Duration `long:"retry-max"     default:"5m" description:"The maximum time between retries when logging in or re-authing a secret."`
	RetryInitial  time.Duration `long:"retry-initial" default:"1s" description:"The initial time between retries when logging in or re-authing a secret."`

	Params []template.VarKV `long:"auth-param"  description:"Paramter to pass when logging in via the backend. Can be specified multiple times." value-name:"NAME=VALUE"`
}

func (manager VaultManager) IsConfigured() bool {
	return manager.URL != ""
}

func (manager VaultManager) Validate() error {
	_, err := url.Parse(manager.URL)
	if err != nil {
		return fmt.Errorf("invalid URL: %s", err)
	}

	if manager.Auth.ClientToken != "" {
		return nil
	}

	if manager.Auth.Backend != "" {
		return nil
	}

	return errors.New("must configure client token or auth backend")
}

func (manager VaultManager) NewVariablesFactory(logger lager.Logger) (creds.VariablesFactory, error) {
	tlsConfig := &vaultapi.TLSConfig{
		CACert:        manager.TLS.CACert,
		CAPath:        manager.TLS.CAPath,
		TLSServerName: manager.TLS.ServerName,
		Insecure:      manager.TLS.Insecure,

		ClientCert: manager.TLS.ClientCert,
		ClientKey:  manager.TLS.ClientKey,
	}

	c, err := NewAPIClient(logger, manager.URL, tlsConfig, manager.Auth)
	if err != nil {
		return nil, err
	}

	ra := NewReAuther(c, manager.Auth.BackendMaxTTL, manager.Auth.RetryInitial, manager.Auth.RetryMax)
	var sr SecretReader = c
	if manager.Cache {
		sr = NewCache(c, manager.MaxLease)
	}

	return NewVaultFactory(sr, ra.LoggedIn(), manager.PathPrefix), nil
}
<commit_msg>Fixing cache attribute in VaultManager<commit_after>package vault

import (
	"errors"
	"fmt"
	"net/url"
	"time"

	"code.cloudfoundry.org/lager"

	"github.com/cloudfoundry/bosh-cli/director/template"
	"github.com/concourse/atc/creds"
	vaultapi "github.com/hashicorp/vault/api"
)

type VaultManager struct {
	URL string `long:"url" description:"Vault server address used to access secrets."`

	PathPrefix string `long:"path-prefix" default:"/concourse" description:"Path under which to namespace credential lookup."`

	Cache    bool          `long:"cache" default:"false" description:"Cache returned secrets for their lease duration in memory"`
	MaxLease time.Duration `long:"max-lease" description:"If the cache is enabled, and this is set, override secrets lease duration with a maximum value"`

	TLS struct {
		CACert     string `long:"ca-cert"              description:"Path to a PEM-encoded CA cert file to use to verify the vault server SSL cert."`
		CAPath     string `long:"ca-path"              description:"Path to a directory of PEM-encoded CA cert files to verify the vault server SSL cert."`
		ClientCert string `long:"client-cert"          description:"Path to the client certificate for Vault authorization."`
		ClientKey  string `long:"client-key"           description:"Path to the client private key for Vault authorization."`
		ServerName string `long:"server-name"          description:"If set, is used to set the SNI host when connecting via TLS."`
		Insecure   bool   `long:"insecure-skip-verify" description:"Enable insecure SSL verification."`
	}

	Auth AuthConfig
}

type AuthConfig struct {
	ClientToken string `long:"client-token" description:"Client token for accessing secrets within the Vault server."`

	Backend       string        `long:"auth-backend"               description:"Auth backend to use for logging in to Vault."`
	BackendMaxTTL time.Duration `long:"auth-backend-max-ttl"       description:"Time after which to force a re-login. If not set, the token will just be continuously renewed."`
	RetryMax      time.Duration `long:"retry-max"     default:"5m" description:"The maximum time between retries when logging in or re-authing a secret."`
	RetryInitial  time.Duration `long:"retry-initial" default:"1s" description:"The initial time between retries when logging in or re-authing a secret."`

	Params []template.VarKV `long:"auth-param"  description:"Paramter to pass when logging in via the backend. Can be specified multiple times." value-name:"NAME=VALUE"`
}

func (manager VaultManager) IsConfigured() bool {
	return manager.URL != ""
}

func (manager VaultManager) Validate() error {
	_, err := url.Parse(manager.URL)
	if err != nil {
		return fmt.Errorf("invalid URL: %s", err)
	}

	if manager.Auth.ClientToken != "" {
		return nil
	}

	if manager.Auth.Backend != "" {
		return nil
	}

	return errors.New("must configure client token or auth backend")
}

func (manager VaultManager) NewVariablesFactory(logger lager.Logger) (creds.VariablesFactory, error) {
	tlsConfig := &vaultapi.TLSConfig{
		CACert:        manager.TLS.CACert,
		CAPath:        manager.TLS.CAPath,
		TLSServerName: manager.TLS.ServerName,
		Insecure:      manager.TLS.Insecure,

		ClientCert: manager.TLS.ClientCert,
		ClientKey:  manager.TLS.ClientKey,
	}

	c, err := NewAPIClient(logger, manager.URL, tlsConfig, manager.Auth)
	if err != nil {
		return nil, err
	}

	ra := NewReAuther(c, manager.Auth.BackendMaxTTL, manager.Auth.RetryInitial, manager.Auth.RetryMax)
	var sr SecretReader = c
	if manager.Cache {
		sr = NewCache(c, manager.MaxLease)
	}

	return NewVaultFactory(sr, ra.LoggedIn(), manager.PathPrefix), nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Dmitry Vyukov. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package snappy

import (
	"github.com/golang/snappy/snappy"
)

func Fuzz(data []byte) int {
	n, err := snappy.DecodedLen(data)
	if err != nil || n > 1e6 {
		return 0
	}
	if n < 0 {
		panic("negative decoded len")
	}
	dec, err := snappy.Decode(nil, data)
	if err != nil {
		if dec != nil {
			panic("dec is not nil")
		}
		return 0
	}
	if len(dec) != n {
		println(len(dec), n)
		panic("bad decoded len")
	}
	n = snappy.MaxEncodedLen(len(dec))
	enc, err := snappy.Encode(nil, dec)
	if err != nil {
		panic(err)
	}
	if len(enc) > n {
		panic("bad encoded len")
	}
	return 1
}
<commit_msg>fix and extend snappy test<commit_after>// Copyright 2015 Dmitry Vyukov. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package snappy

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

	"github.com/golang/snappy"
)

func Fuzz(data []byte) int {
	n, err := snappy.DecodedLen(data)
	if err != nil || n > 1e6 {
		return 0
	}
	if n < 0 {
		panic("negative decoded len")
	}
	dec, err := snappy.Decode(nil, data)
	if err != nil {
		if dec != nil {
			panic("dec is not nil")
		}
		return 0
	}
	if len(dec) != n {
		println(len(dec), n)
		panic("bad decoded len")
	}
	n = snappy.MaxEncodedLen(len(dec))
	enc := snappy.Encode(nil, dec)
	if len(enc) > n {
		panic("bad encoded len")
	}

	dec1, err := snappy.Decode(nil, enc)
	if err != nil {
		panic(err)
	}
	if bytes.Compare(dec, dec1) != 0 {
		panic("not equal")
	}
	return 1
}

func FuzzFraming(data []byte) int {
	r := snappy.NewReader(bytes.NewReader(data))
	buf := make([]byte, 0, 1023)
	dec := make([]byte, 0, 1024)
	for i := 0; ; i++ {
		x := i
		if x > cap(buf) {
			x = cap(buf)
		}
		n, err := r.Read(buf[:x])
		if n != 0 {
			dec = append(dec, buf[:n]...)
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			return 0
		}
	}
	r.Reset(bytes.NewReader(data))
	dec1, err := ioutil.ReadAll(r)
	if err != nil {
		panic(err)
	}
	if bytes.Compare(dec, dec1) != 0 {
		fmt.Printf("dec0: %q\n", dec)
		fmt.Printf("dec1: %q\n", dec1)
		panic("not equal")
	}

	bufw := new(bytes.Buffer)
	w := snappy.NewBufferedWriter(bufw)
	for i := 0; len(dec1) > 0; i++ {
		x := i
		if x > len(dec1) {
			x = len(dec1)
		}
		n, err := w.Write(dec1[:x])
		if n != x {
			panic("short write")
		}
		if err != nil {
			panic(err)
		}
		dec1 = dec1[x:]
		if (i % 2) != 0 {
			w.Flush()
		}
	}
	w.Close()

	dec1 = append([]byte{}, dec...)
	bufw2 := new(bytes.Buffer)
	w2 := snappy.NewWriter(bufw2)
	for i := 2; len(dec1) > 0; i++ {
		x := i
		if x > len(dec1) {
			x = len(dec1)
		}
		n, err := w2.Write(dec1[:x])
		if n != x {
			panic("short write")
		}
		if err != nil {
			panic(err)
		}
		dec1 = dec1[x:]
		if (i % 2) != 0 {
			w2.Flush()
		}
	}
	w2.Close()

	r2 := snappy.NewReader(bufw)
	dec2, err := ioutil.ReadAll(r2)
	if err != nil {
		panic(err)
	}
	if bytes.Compare(dec, dec2) != 0 {
		panic("not equal")
	}

	r3 := snappy.NewReader(bufw2)
	dec3, err := ioutil.ReadAll(r3)
	if err != nil {
		panic(err)
	}
	if bytes.Compare(dec, dec3) != 0 {
		panic("not equal")
	}

	return 1
}
<|endoftext|>