<commit_before>package llvm_module

import (
	"github.com/grainlang/grain/ast"
	"llvm.org/llvm/bindings/go/llvm"
	"strconv"
)

func CreateLlvmModuleFromFunction(function ast.Function, allFunctions []ast.Function) llvm.Module {
	context := llvm.GlobalContext()
	builder := context.NewBuilder()
	module := context.NewModule(function.Id + " " + function.Name)
	llvmFunction := createFunctionDeclarationInModule(function, module)
	bodyBlock := llvm.AddBasicBlock(llvmFunction, "body")
	builder.SetInsertPoint(bodyBlock, bodyBlock.FirstInstruction())
	returnValueToLlvmValue := make(map[string]llvm.Value)
	functionToLlvmDeclaration := make(map[string]llvm.Value)
	returnBindings := make([]llvm.Value, 0)
	for _, body := range function.Body {
		switch typedBody := body.(type) {
		case ast.NativeFunctionCall:
			nativeFunctionParamTypes := make([]llvm.Type, len(typedBody.Parameters))
			for i := range typedBody.Parameters {
				nativeFunctionParamTypes[i] = llvm.Int32Type()
			}
			var nativeFunctionReturnType llvm.Type
			if typedBody.ReturnType == ast.NativeValueVoid {
				nativeFunctionReturnType = llvm.VoidType()
			} else if typedBody.ReturnType == ast.NativeValueInt {
				nativeFunctionReturnType = llvm.Int32Type()
			} else {
				panic("Unknown type")
			}
			nativeFunctionType := llvm.FunctionType(nativeFunctionReturnType, nativeFunctionParamTypes, false)
			nativeFunction := llvm.AddFunction(module, typedBody.Name, nativeFunctionType)
			nativeFunctionParamValues := make([]llvm.Value, len(typedBody.Parameters))
			for i, nativeFunctionParam := range typedBody.Parameters {
				for index, param := range function.Parameters {
					if nativeFunctionParam.Id == param.Id {
						nativeFunctionParamValues[i] = llvmFunction.Param(index)
						break
					}
				}
			}
			nativeFunctionReturnValue := builder.CreateCall(nativeFunction, nativeFunctionParamValues, "ret")
			returnValueToLlvmValue[typedBody.Id + " " + typedBody.ReturnId] = nativeFunctionReturnValue
		case ast.BinaryOperationCall:
			var opcode llvm.Opcode
			if typedBody.Name == "+" {
				opcode = llvm.Add
			} else if typedBody.Name == "-" {
				opcode = llvm.Sub
			} else if typedBody.Name == "*" {
				opcode = llvm.Mul
			} else if typedBody.Name == "/" {
				opcode = llvm.SDiv
			} else if typedBody.Name == "%" {
				opcode = llvm.SRem
			} else {
				panic("Unknown operator: " + typedBody.Name)
			}
			var leftParam, rightParam llvm.Value
			for index, param := range function.Parameters {
				if typedBody.LeftParameter.Id == param.Id {
					leftParam = llvmFunction.Param(index)
				} else if typedBody.RightParameter.Id == param.Id {
					rightParam = llvmFunction.Param(index)
				}
			}
			binaryOperationReturnValue := builder.CreateBinOp(opcode, leftParam, rightParam, "ret")
			returnValueToLlvmValue[typedBody.Id + " " + typedBody.ReturnId] = binaryOperationReturnValue
		case ast.FunctionUse:
			consumingFunction := FindUsedFunction(typedBody, allFunctions)
			var consumingLlvmFunction llvm.Value
			if foundDeclaration, ok := functionToLlvmDeclaration[consumingFunction.Id]; ok {
				consumingLlvmFunction = foundDeclaration
			} else {
				consumingLlvmFunction = createFunctionDeclarationInModule(consumingFunction, module)
				functionToLlvmDeclaration[consumingFunction.Id] = consumingLlvmFunction
			}
			llvmParams := make([]llvm.Value, len(typedBody.Bindings))
			for i, binding := range typedBody.Bindings {
				llvmParams[i] = returnValueToLlvmValue[binding.FromId + " " + binding.FromReturnValue]
			}
			consumingFunctionReturnValue := builder.CreateCall(consumingLlvmFunction, llvmParams, "ret")
			for i, returnValue := range consumingFunction.ReturnValues {
				element := builder.CreateExtractValue(consumingFunctionReturnValue, i, "elem" + strconv.Itoa(i))
				returnValueToLlvmValue[typedBody.Id + " " + returnValue.Id] = element
			}
		case ast.Binding:
			returnBindings = append(returnBindings, returnValueToLlvmValue[typedBody.FromId + " " + typedBody.FromReturnValue])
		}
	}
	builder.CreateAggregateRet(returnBindings)
	return module
}

func createFunctionDeclarationInModule(function ast.Function, module llvm.Module) llvm.Value {
	paramTypes := make([]llvm.Type, len(function.Parameters))
	for i, param := range function.Parameters {
		if param.ValueType == ast.Integer {
			paramTypes[i] = llvm.Int64Type()
		} else {
			paramTypes[i] = llvm.Int32Type()
		}
	}
	returnTypes := make([]llvm.Type, len(function.ReturnValues))
	for i, returnValue := range function.ReturnValues {
		if returnValue.ValueType == ast.Integer {
			returnTypes[i] = llvm.Int32Type()
		} else {
			returnTypes[i] = llvm.Int32Type()
		}
	}
	returnType := llvm.StructType(returnTypes, false)
	llvmFunctionType := llvm.FunctionType(returnType, paramTypes, false)
	llvmFunction := llvm.AddFunction(module, "$" + function.Id, llvmFunctionType)
	return llvmFunction
}

func FindUsedFunction(bodyPart ast.FunctionUse, allFunctions []ast.Function) ast.Function {
	for _, fn := range allFunctions {
		if bodyPart.FunctionId == fn.Id {
			return fn
		}
	}
	panic("No such function " + bodyPart.FunctionId)
}<commit_msg>Use return value names in LLVM IR.<commit_after>package llvm_module

import (
	"github.com/grainlang/grain/ast"
	"llvm.org/llvm/bindings/go/llvm"
	"strconv"
)

func CreateLlvmModuleFromFunction(function ast.Function, allFunctions []ast.Function) llvm.Module {
	context := llvm.GlobalContext()
	builder := context.NewBuilder()
	module := context.NewModule(function.Id + " " + function.Name)
	llvmFunction := createFunctionDeclarationInModule(function, module)
	bodyBlock := llvm.AddBasicBlock(llvmFunction, "body")
	builder.SetInsertPoint(bodyBlock, bodyBlock.FirstInstruction())
	returnValueToLlvmValue := make(map[string]llvm.Value)
	functionToLlvmDeclaration := make(map[string]llvm.Value)
	returnBindings := make([]llvm.Value, 0)
	for _, body := range function.Body {
		switch typedBody := body.(type) {
		case ast.NativeFunctionCall:
			nativeFunctionParamTypes := make([]llvm.Type, len(typedBody.Parameters))
			for i := range typedBody.Parameters {
				nativeFunctionParamTypes[i] = llvm.Int32Type()
			}
			var nativeFunctionReturnType llvm.Type
			if typedBody.ReturnType == ast.NativeValueVoid {
				nativeFunctionReturnType = llvm.VoidType()
			} else if typedBody.ReturnType == ast.NativeValueInt {
				nativeFunctionReturnType = llvm.Int32Type()
			} else {
				panic("Unknown type")
			}
			nativeFunctionType := llvm.FunctionType(nativeFunctionReturnType, nativeFunctionParamTypes, false)
			nativeFunction := llvm.AddFunction(module, typedBody.Name, nativeFunctionType)
			nativeFunctionParamValues := make([]llvm.Value, len(typedBody.Parameters))
			for i, nativeFunctionParam := range typedBody.Parameters {
				for index, param := range function.Parameters {
					if nativeFunctionParam.Id == param.Id {
						nativeFunctionParamValues[i] = llvmFunction.Param(index)
						break
					}
				}
			}
			nativeFunctionReturnValue := builder.CreateCall(nativeFunction, nativeFunctionParamValues, "ret")
			returnValueToLlvmValue[typedBody.Id + " " + typedBody.ReturnId] = nativeFunctionReturnValue
		case ast.BinaryOperationCall:
			var opcode llvm.Opcode
			if typedBody.Name == "+" {
				opcode = llvm.Add
			} else if typedBody.Name == "-" {
				opcode = llvm.Sub
			} else if typedBody.Name == "*" {
				opcode = llvm.Mul
			} else if typedBody.Name == "/" {
				opcode = llvm.SDiv
			} else if typedBody.Name == "%" {
				opcode = llvm.SRem
			} else {
				panic("Unknown operator: " + typedBody.Name)
			}
			var leftParam, rightParam llvm.Value
			for index, param := range function.Parameters {
				if typedBody.LeftParameter.Id == param.Id {
					leftParam = llvmFunction.Param(index)
				} else if typedBody.RightParameter.Id == param.Id {
					rightParam = llvmFunction.Param(index)
				}
			}
			binaryOperationReturnValue := builder.CreateBinOp(opcode, leftParam, rightParam, "ret")
			returnValueToLlvmValue[typedBody.Id + " " + typedBody.ReturnId] = binaryOperationReturnValue
		case ast.FunctionUse:
			consumingFunction := FindUsedFunction(typedBody, allFunctions)
			var consumingLlvmFunction llvm.Value
			if foundDeclaration, ok := functionToLlvmDeclaration[consumingFunction.Id]; ok {
				consumingLlvmFunction = foundDeclaration
			} else {
				consumingLlvmFunction = createFunctionDeclarationInModule(consumingFunction, module)
				functionToLlvmDeclaration[consumingFunction.Id] = consumingLlvmFunction
			}
			llvmParams := make([]llvm.Value, len(typedBody.Bindings))
			for i, binding := range typedBody.Bindings {
				llvmParams[i] = returnValueToLlvmValue[binding.FromId + " " + binding.FromReturnValue]
			}
			consumingFunctionReturnValue := builder.CreateCall(consumingLlvmFunction, llvmParams, "ret")
			for i, returnValue := range consumingFunction.ReturnValues {
				var name string
				if returnValue.Name != "" {
					name = returnValue.Name
				} else {
					name = "elem" + strconv.Itoa(i)
				}
				element := builder.CreateExtractValue(consumingFunctionReturnValue, i, name)
				returnValueToLlvmValue[typedBody.Id + " " + returnValue.Id] = element
			}
		case ast.Binding:
			returnBindings = append(returnBindings, returnValueToLlvmValue[typedBody.FromId + " " + typedBody.FromReturnValue])
		}
	}
	builder.CreateAggregateRet(returnBindings)
	return module
}

func createFunctionDeclarationInModule(function ast.Function, module llvm.Module) llvm.Value {
	paramTypes := make([]llvm.Type, len(function.Parameters))
	for i, param := range function.Parameters {
		if param.ValueType == ast.Integer {
			paramTypes[i] = llvm.Int64Type()
		} else {
			paramTypes[i] = llvm.Int32Type()
		}
	}
	returnTypes := make([]llvm.Type, len(function.ReturnValues))
	for i, returnValue := range function.ReturnValues {
		if returnValue.ValueType == ast.Integer {
			returnTypes[i] = llvm.Int32Type()
		} else {
			returnTypes[i] = llvm.Int32Type()
		}
	}
	returnType := llvm.StructType(returnTypes, false)
	llvmFunctionType := llvm.FunctionType(returnType, paramTypes, false)
	llvmFunction := llvm.AddFunction(module, "$" + function.Id, llvmFunctionType)
	return llvmFunction
}

func FindUsedFunction(bodyPart ast.FunctionUse, allFunctions []ast.Function) ast.Function {
	for _, fn := range allFunctions {
		if bodyPart.FunctionId == fn.Id {
			return fn
		}
	}
	panic("No such function " + bodyPart.FunctionId)
}<|endoftext|>


<commit_before>package server

import (
	"net"
	"sync"
)

type NodeManager struct {
	params           *NodeManagerParams
	logger           Logger
	wg               sync.WaitGroup
	mu               sync.Mutex
	transportManager *TransportManager
	rooms            map[string]struct{}
}

type NodeManagerParams struct {
	LoggerFactory LoggerFactory
	RoomManager   *ChannelRoomManager
	TracksManager TracksManager
	ListenAddr    *net.UDPAddr
	Nodes         []*net.UDPAddr
}

func NewNodeManager(params NodeManagerParams) (*NodeManager, error) {
	conn, err := net.ListenUDP("udp", params.ListenAddr)

	if err != nil {
		return nil, err
	}

	transportManager := NewTransportManager(TransportManagerParams{
		Conn:          conn,
		LoggerFactory: params.LoggerFactory,
	})

	nm := &NodeManager{
		params:           &params,
		transportManager: transportManager,
		logger:           params.LoggerFactory.GetLogger("nodemanager"),
		rooms:            map[string]struct{}{},
	}

	for _, addr := range params.Nodes {
		factory, err := transportManager.GetTransportFactory(addr)
		if err != nil {
			nm.logger.Println("Error creating transport factory for remote addr: %s", addr)
		}

		nm.handleServerTransportFactory(factory)
	}

	go nm.startTransportEventLoop()
	go nm.startRoomEventLoop()

	return nm, nil
}

func (nm *NodeManager) startTransportEventLoop() {
	for {
		factory, err := nm.transportManager.AcceptTransportFactory()
		if err != nil {
			nm.logger.Printf("Error accepting transport factory: %s", err)
			return
		}

		nm.handleServerTransportFactory(factory)
	}
}

func (nm *NodeManager) handleServerTransportFactory(factory *ServerTransportFactory) {
	nm.wg.Add(1)
	go func() {
		defer nm.wg.Done()

		doneChan := make(chan struct{})
		closeChannelOnce := sync.Once{}

		done := func() {
			closeChannelOnce.Do(func() {
				close(doneChan)
			})
		}

		for {
			select {
			case <-doneChan:
				nm.logger.Printf("Aborting server transport factory goroutine")
				return
			default:
			}
			transportPromise := factory.AcceptTransport()
			nm.handleTransportPromise(transportPromise)

			nm.wg.Add(1)
			go func(p *TransportPromise) {
				defer nm.wg.Done()

				_, err := p.Wait()
				if err != nil {
					nm.logger.Printf("Error while waiting for TransportPromise: %s", err)
					done()
				}
			}(transportPromise)
		}
	}()
}

func (nm *NodeManager) handleTransportPromise(transportPromise *TransportPromise) {
	nm.wg.Add(1)

	go func() {
		defer nm.wg.Done()

		streamTransport, err := transportPromise.Wait()

		if err != nil {
			nm.logger.Printf("Error waiting for transport promise: %s", err)
			return
		}

		nm.mu.Lock()
		defer nm.mu.Unlock()

		nm.params.TracksManager.Add(transportPromise.StreamID(), streamTransport)
	}()
}

func (nm *NodeManager) startRoomEventLoop() {
	for {
		roomEvent, err := nm.params.RoomManager.AcceptEvent()
		if err != nil {
			nm.logger.Printf("Error accepting room event: %s", err)
			return
		}

		switch roomEvent.Type {
		case RoomEventTypeAdd:
			for _, factory := range nm.transportManager.Factories() {
				transportPromise := factory.NewTransport(roomEvent.RoomName)
				nm.handleTransportPromise(transportPromise)
			}
		case RoomEventTypeRemove:
			for _, factory := range nm.transportManager.Factories() {
				factory.CloseTransport(roomEvent.RoomName)
			}
		}
	}
}

func (nm *NodeManager) Close() error {
	nm.params.RoomManager.Close()
	nm.transportManager.Close()

	nm.wg.Wait()

	return nil
}
<commit_msg>Log listen UDP conn addr<commit_after>package server

import (
	"net"
	"sync"
)

type NodeManager struct {
	params           *NodeManagerParams
	logger           Logger
	wg               sync.WaitGroup
	mu               sync.Mutex
	transportManager *TransportManager
	rooms            map[string]struct{}
}

type NodeManagerParams struct {
	LoggerFactory LoggerFactory
	RoomManager   *ChannelRoomManager
	TracksManager TracksManager
	ListenAddr    *net.UDPAddr
	Nodes         []*net.UDPAddr
}

func NewNodeManager(params NodeManagerParams) (*NodeManager, error) {
	logger := params.LoggerFactory.GetLogger("nodemanager")

	conn, err := net.ListenUDP("udp", params.ListenAddr)

	if err != nil {
		return nil, err
	}

	logger.Printf("Listening on UDP port: %s", conn.LocalAddr().String())

	transportManager := NewTransportManager(TransportManagerParams{
		Conn:          conn,
		LoggerFactory: params.LoggerFactory,
	})

	nm := &NodeManager{
		params:           &params,
		transportManager: transportManager,
		logger:           logger,
		rooms:            map[string]struct{}{},
	}

	for _, addr := range params.Nodes {
		logger.Printf("Configuring remote node: %s", addr.String())

		factory, err := transportManager.GetTransportFactory(addr)
		if err != nil {
			nm.logger.Println("Error creating transport factory for remote addr: %s", addr)
		}

		nm.handleServerTransportFactory(factory)
	}

	go nm.startTransportEventLoop()
	go nm.startRoomEventLoop()

	return nm, nil
}

func (nm *NodeManager) startTransportEventLoop() {
	for {
		factory, err := nm.transportManager.AcceptTransportFactory()
		if err != nil {
			nm.logger.Printf("Error accepting transport factory: %s", err)
			return
		}

		nm.handleServerTransportFactory(factory)
	}
}

func (nm *NodeManager) handleServerTransportFactory(factory *ServerTransportFactory) {
	nm.wg.Add(1)
	go func() {
		defer nm.wg.Done()

		doneChan := make(chan struct{})
		closeChannelOnce := sync.Once{}

		done := func() {
			closeChannelOnce.Do(func() {
				close(doneChan)
			})
		}

		for {
			select {
			case <-doneChan:
				nm.logger.Printf("Aborting server transport factory goroutine")
				return
			default:
			}
			transportPromise := factory.AcceptTransport()
			nm.handleTransportPromise(transportPromise)

			nm.wg.Add(1)
			go func(p *TransportPromise) {
				defer nm.wg.Done()

				_, err := p.Wait()
				if err != nil {
					nm.logger.Printf("Error while waiting for TransportPromise: %s", err)
					done()
				}
			}(transportPromise)
		}
	}()
}

func (nm *NodeManager) handleTransportPromise(transportPromise *TransportPromise) {
	nm.wg.Add(1)

	go func() {
		defer nm.wg.Done()

		streamTransport, err := transportPromise.Wait()

		if err != nil {
			nm.logger.Printf("Error waiting for transport promise: %s", err)
			return
		}

		nm.mu.Lock()
		defer nm.mu.Unlock()

		nm.params.TracksManager.Add(transportPromise.StreamID(), streamTransport)
	}()
}

func (nm *NodeManager) startRoomEventLoop() {
	for {
		roomEvent, err := nm.params.RoomManager.AcceptEvent()
		if err != nil {
			nm.logger.Printf("Error accepting room event: %s", err)
			return
		}

		switch roomEvent.Type {
		case RoomEventTypeAdd:
			for _, factory := range nm.transportManager.Factories() {
				transportPromise := factory.NewTransport(roomEvent.RoomName)
				nm.handleTransportPromise(transportPromise)
			}
		case RoomEventTypeRemove:
			for _, factory := range nm.transportManager.Factories() {
				factory.CloseTransport(roomEvent.RoomName)
			}
		}
	}
}

func (nm *NodeManager) Close() error {
	nm.params.RoomManager.Close()
	nm.transportManager.Close()

	nm.wg.Wait()

	return nil
}
<|endoftext|>


<commit_before>package shark

import(
	tp "tritium/proto"
	"libxml/xpath"
	"rubex"
	proto "goprotobuf.googlecode.com/hg/proto"
)

type Shark struct {
	RegexpCache map[string]*rubex.Regexp
	XPathCache map[string]*xpath.Expression
}

type Ctx struct {
	Functions []*Function
	Types []string
	Exports [][]string
	Logs []string
	Env map[string]string
	*Shark
	*tp.Transform
}

type Function struct {
	Name string
	*tp.Function
}

type Scope struct {
	Value interface{}
}

func NewEngine() (*Shark) {
	e := &Shark{
		RegexpCache: make(map[string]*rubex.Regexp),
		XPathCache: make(map[string]*xpath.Expression),
	}
	return e
}

func (ctx *Ctx) UsePackage(pkg *tp.Package) {
	ctx.Types = make([]string, len(pkg.Types))
	for i, t := range(pkg.Types) {
		ctx.Types[i] = proto.GetString(t.Name)
	}

	ctx.Functions = make([]*Function, len(pkg.Functions))
	for i, f := range(pkg.Functions) {
		fun := &Function{
			Name: proto.GetString(f.Name),
			Function: f,
		}
		ctx.Functions[i] = fun
	}
}

func (eng *Shark) Run(transform *tp.Transform, input string, vars map[string]string) (data string, exports [][]string, logs []string) {
	ctx := &Ctx{
		Shark: eng,
		Exports: make([][]string, 0),
		Logs: make([]string, 0),
		Env: make(map[string]string),
		Transform: transform,
	}
	ctx.UsePackage(transform.Pkg)
	scope := &Scope{Value:input}
	ctx.runInstruction(scope, transform.Objects[0].Root)
	data = scope.Value.(string)
	return
}

func (ctx *Ctx) runInstruction(scope *Scope, ins *tp.Instruction) (returnValue interface{}) {
	returnValue = ""
	switch *ins.Type {
	case tp.Instruction_BLOCK:
		for _, child := range(ins.Children) {
			returnValue = ctx.runInstruction(scope, child)
		}
	case tp.Instruction_TEXT:
		returnValue = proto.GetString(ins.Value)
	case tp.Instruction_FUNCTION_CALL:
		fun := ctx.Functions[int(proto.GetInt32(ins.FunctionId))]
		args := make([]interface{}, len(ins.Arguments))
		for i, argIns := range(ins.Arguments) {
			args[i] = ctx.runInstruction(scope, argIns)
		}
		if proto.GetBool(fun.BuiltIn) {
			switch fun.Name {
			case "concat":
				returnValue = args[0].(string) + args[1].(string)
			case "var":
				ts := &Scope{Value: ctx.Env[args[0].(string)]}
				ctx.runChildren(ts, ins)
				returnValue = ts.Value
				ctx.Env[args[0].(string)] = returnValue.(string)
			case "set":
				scope.Value = args[0]
			case "log":
				ctx.Logs = append(ctx.Logs, args[0].(string))
			default:
				println("Must implement", fun.Name)
			}

		} else {
			println("Not Built in!")
		}
	}
	return
}

func (ctx *Ctx) runChildren(scope *Scope, ins *tp.Instruction) (returnValue interface{}) {
	for _, child := range(ins.Children) {
		returnValue = ctx.runInstruction(scope, child)
	}
	return
}
<commit_msg>implementation of export<commit_after>package shark

import(
	tp "tritium/proto"
	"libxml/xpath"
	"rubex"
	proto "goprotobuf.googlecode.com/hg/proto"
)

type Shark struct {
	RegexpCache map[string]*rubex.Regexp
	XPathCache map[string]*xpath.Expression
}

type Ctx struct {
	Functions []*Function
	Types []string
	Exports [][]string
	Logs []string
	Env map[string]string
	LocalVars map[string]interface{}
	*Shark
	*tp.Transform
}

type Function struct {
	Name string
	*tp.Function
}

type Scope struct {
	Value interface{}
}

func NewEngine() (*Shark) {
	e := &Shark{
		RegexpCache: make(map[string]*rubex.Regexp),
		XPathCache: make(map[string]*xpath.Expression),
	}
	return e
}

func (ctx *Ctx) UsePackage(pkg *tp.Package) {
	ctx.Types = make([]string, len(pkg.Types))
	for i, t := range(pkg.Types) {
		ctx.Types[i] = proto.GetString(t.Name)
	}

	ctx.Functions = make([]*Function, len(pkg.Functions))
	for i, f := range(pkg.Functions) {
		name := proto.GetString(f.Name)
		for _, a := range(f.Args) {
			typeString := ctx.Types[int(proto.GetInt32(a.TypeId))]
			name = name + "." + typeString
		}
		fun := &Function{
			Name: name,
			Function: f,
		}
		ctx.Functions[i] = fun
	}
}

func (eng *Shark) Run(transform *tp.Transform, input string, vars map[string]string) (data string, exports [][]string, logs []string) {
	ctx := &Ctx{
		Shark: eng,
		Exports: make([][]string, 0),
		Logs: make([]string, 0),
		Env: make(map[string]string),
		Transform: transform,
	}
	ctx.UsePackage(transform.Pkg)
	scope := &Scope{Value:input}
	ctx.runInstruction(scope, transform.Objects[0].Root)
	data = scope.Value.(string)
	return
}

func (ctx *Ctx) runInstruction(scope *Scope, ins *tp.Instruction) (returnValue interface{}) {
	returnValue = ""
	switch *ins.Type {
	case tp.Instruction_BLOCK:
		for _, child := range(ins.Children) {
			returnValue = ctx.runInstruction(scope, child)
		}
	case tp.Instruction_TEXT:
		returnValue = proto.GetString(ins.Value)
	case tp.Instruction_LOCAL_VAR:

	case tp.Instruction_FUNCTION_CALL:
		fun := ctx.Functions[int(proto.GetInt32(ins.FunctionId))]
		args := make([]interface{}, len(ins.Arguments))
		for i, argIns := range(ins.Arguments) {
			args[i] = ctx.runInstruction(scope, argIns)
		}
		if proto.GetBool(fun.BuiltIn) {
			switch fun.Name {
			case "concat.Text.Text":
				returnValue = args[0].(string) + args[1].(string)
			case "var.Text":
				ts := &Scope{Value: ctx.Env[args[0].(string)]}
				ctx.runChildren(ts, ins)
				returnValue = ts.Value
				ctx.Env[args[0].(string)] = returnValue.(string)
			case "export.Text":
				val := make([]string, 2)
				val[0] = args[0].(string)
				ts := &Scope{Value:""}
				ctx.runChildren(ts, ins)
				val[1] = ts.Value.(string)
				ctx.Exports = append(ctx.Exports, val)
			case "set.Text":
				scope.Value = args[0]
			case "log.Text":
				ctx.Logs = append(ctx.Logs, args[0].(string))
			default:
				println("Must implement", fun.Name)
			}

		} else {
			println("Not Built in!")
		}
	}
	return
}

func (ctx *Ctx) runChildren(scope *Scope, ins *tp.Instruction) (returnValue interface{}) {
	for _, child := range(ins.Children) {
		returnValue = ctx.runInstruction(scope, child)
	}
	return
}
<|endoftext|>


<commit_before>// Package sha holds Security Health Analytics finding entities and functions
package sha

// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://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.

import (
	"encoding/json"

	"cloud.google.com/go/pubsub"
	"github.com/googlecloudplatform/threat-automation/entities"
	"github.com/pkg/errors"
)

// Finding common attributes, source properties and security marks
// to all Security Health Analytics Security Command Center findings
type Finding struct {
	NotificationConfigName string
	Finding                struct {
		Name             string
		Parent           string
		ResourceName     string
		State            string
		Category         string
		ExternalURI      string
		SourceProperties struct {
			ReactivationCount     float32
			ExceptionInstructions string
			SeverityLevel         string
			Recommendation        string
			ProjectID             string
			DeactivationReason    string
			AssetCreationTime     string
			ScannerName           string
			ScanRunID             string
			Explanation           string
		}
		SecurityMarks struct {
			Name  string
			Marks map[string]string
		}
		EventTime  string
		CreateTime string
	}
}

// NewFinding returns a new ShaFinding.
func NewFinding(m *pubsub.Message) (*Finding, error) {
	f := Finding{}

	if err := json.Unmarshal(m.Data, &f); err != nil {
		return nil, errors.Wrap(err, "failed to unmarshal")
	}
	if f.Finding.ResourceName == "" {
		return nil, errors.Wrap(entities.ErrValueNotFound, "does not have a resource name")
	}

	if f.Finding.Category == "" {
		return nil, errors.Wrap(entities.ErrValueNotFound, "does not have a category")
	}

	return &f, nil
}

// ResourceName returns the finding ResourceName
func (f *Finding) ResourceName() string {
	return f.Finding.ResourceName
}

// Category returns the finding Category
func (f *Finding) Category() string {
	return f.Finding.Category
}

// ScannerName returns the Security Health Analytics finding ScannerName
func (f *Finding) ScannerName() string {
	return f.Finding.SourceProperties.ScannerName
}

// ProjectID returns the Security Health Analytics finding ProjectID
func (f *Finding) ProjectID() string {
	return f.Finding.SourceProperties.ProjectID
}
<commit_msg>Add validation func<commit_after>// Package sha holds Security Health Analytics finding entities and functions
package sha

// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://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.

import (
	"encoding/json"

	"cloud.google.com/go/pubsub"
	"github.com/googlecloudplatform/threat-automation/entities"
	"github.com/pkg/errors"
)

// Finding common attributes, source properties and security marks
// to all Security Health Analytics Security Command Center findings
type Finding struct {
	NotificationConfigName string
	Finding                struct {
		Name             string
		Parent           string
		ResourceName     string
		State            string
		Category         string
		ExternalURI      string
		SourceProperties struct {
			ReactivationCount     float32
			ExceptionInstructions string
			SeverityLevel         string
			Recommendation        string
			ProjectID             string
			DeactivationReason    string
			AssetCreationTime     string
			ScannerName           string
			ScanRunID             string
			Explanation           string
		}
		SecurityMarks struct {
			Name  string
			Marks map[string]string
		}
		EventTime  string
		CreateTime string
	}
}

// NewFinding returns a new ShaFinding.
func NewFinding(m *pubsub.Message) (*Finding, error) {
	f := Finding{}

	if err := json.Unmarshal(m.Data, &f); err != nil {
		return nil, errors.Wrap(err, "failed to unmarshal")
	}

	if err := f.validate(); err != nil {
		return nil, err
	}

	return &f, nil
}

func (f *Finding) validate() error {

	if f.Finding.ResourceName == "" {
		return errors.Wrap(entities.ErrValueNotFound, "does not have a resource name")
	}

	if f.Finding.Category == "" {
		return errors.Wrap(entities.ErrValueNotFound, "does not have a category")
	}

	return nil

}

// ResourceName returns the finding ResourceName
func (f *Finding) ResourceName() string {
	return f.Finding.ResourceName
}

// Category returns the finding Category
func (f *Finding) Category() string {
	return f.Finding.Category
}

// ScannerName returns the Security Health Analytics finding ScannerName
func (f *Finding) ScannerName() string {
	return f.Finding.SourceProperties.ScannerName
}

// ProjectID returns the Security Health Analytics finding ProjectID
func (f *Finding) ProjectID() string {
	return f.Finding.SourceProperties.ProjectID
}
<|endoftext|>


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

package docker

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"strconv"
	"strings"
	"syscall"

	"code.google.com/p/go.crypto/ssh/terminal"
	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/cmd/tsuru-base"
	"github.com/tsuru/tsuru/errors"
	tsuruIo "github.com/tsuru/tsuru/io"
	"launchpad.net/gnuflag"
)

var httpHeaderRegexp = regexp.MustCompile(`HTTP/.*? (\d+)`)

type moveContainersCmd struct{}

type progressFormatter struct{}

func (progressFormatter) Format(out io.Writer, data []byte) error {
	var logEntry progressLog
	err := json.Unmarshal(data, &logEntry)
	if err != nil {
		return err
	}
	fmt.Fprintf(out, "%s\n", logEntry.Message)
	return nil
}

func (c *moveContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "containers-move",
		Usage:   "containers-move <from host> <to host>",
		Desc:    "Move all containers from one host to another.\nThis command is especially useful for host maintenance.",
		MinArgs: 2,
	}
}

func (c *moveContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL("/docker/containers/move")
	if err != nil {
		return err
	}
	params := map[string]string{
		"from": context.Args[0],
		"to":   context.Args[1],
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

type fixContainersCmd struct{}

func (fixContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:  "fix-containers",
		Usage: "fix-containers",
		Desc:  "Fix containers that are broken in the cluster.",
	}
}

func (fixContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL("/docker/fix-containers")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	return err
}

type moveContainerCmd struct{}

func (c *moveContainerCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "container-move",
		Usage:   "container-move <container id> <to host>",
		Desc:    "Move specified container to another host.",
		MinArgs: 2,
	}
}

func (c *moveContainerCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL(fmt.Sprintf("/docker/container/%s/move", context.Args[0]))
	if err != nil {
		return err
	}
	params := map[string]string{
		"to": context.Args[1],
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

type rebalanceContainersCmd struct {
	tsuru.ConfirmationCommand
	fs  *gnuflag.FlagSet
	dry bool
}

func (c *rebalanceContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "containers-rebalance",
		Usage:   "containers-rebalance [--dry] [-y/--assume-yes]",
		Desc:    "Move containers creating a more even distribution between docker nodes.",
		MinArgs: 0,
	}
}

func (c *rebalanceContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	if !c.dry && !c.Confirm(context, "Are you sure you want to rebalance containers?") {
		return nil
	}
	url, err := cmd.GetURL("/docker/containers/rebalance")
	if err != nil {
		return err
	}
	params := map[string]string{
		"dry": fmt.Sprintf("%t", c.dry),
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

func (c *rebalanceContainersCmd) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		c.fs = c.ConfirmationCommand.Flags()
		c.fs.BoolVar(&c.dry, "dry", false, "Dry run, only shows what would be done")
	}
	return c.fs
}

type sshToContainerCmd struct{}

func (sshToContainerCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "ssh",
		Usage:   "ssh <container-id>",
		Desc:    "Open a SSH shell to the given container.",
		MinArgs: 1,
	}
}

func (sshToContainerCmd) Run(context *cmd.Context, _ *cmd.Client) error {
	serverURL, err := cmd.GetURL("/docker/ssh/" + context.Args[0])
	if err != nil {
		return err
	}
	request, err := http.NewRequest("GET", serverURL, nil)
	if err != nil {
		return err
	}
	request.Close = true
	token, err := cmd.ReadToken()
	if err == nil {
		request.Header.Set("Authorization", "bearer "+token)
	}
	parsedURL, _ := url.Parse(serverURL)
	conn, err := net.Dial("tcp", parsedURL.Host)
	if err != nil {
		return err
	}
	defer conn.Close()
	request.Write(conn)
	if stdin, ok := context.Stdin.(*os.File); ok {
		fd := int(stdin.Fd())
		if terminal.IsTerminal(fd) {
			oldState, err := terminal.MakeRaw(fd)
			if err != nil {
				return err
			}
			defer terminal.Restore(fd, oldState)
			sigChan := make(chan os.Signal, 2)
			go func(c <-chan os.Signal) {
				if _, ok := <-c; ok {
					terminal.Restore(fd, oldState)
					os.Exit(1)
				}
			}(sigChan)
			signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
		}
	}
	bytesLimit := 50
	var readStr string
	byteBuffer := make([]byte, 1)
	for i := 0; i < bytesLimit && byteBuffer[0] != '\n'; i++ {
		_, err := conn.Read(byteBuffer)
		if err != nil {
			break
		}
		readStr += string(byteBuffer)
	}
	matches := httpHeaderRegexp.FindAllStringSubmatch(readStr, -1)
	if len(matches) > 0 && len(matches[0]) > 1 {
		code, _ := strconv.Atoi(matches[0][1])
		return &errors.HTTP{
			Code:    code,
			Message: strings.TrimSpace(readStr),
		}
	} else {
		context.Stdout.Write([]byte(readStr))
	}
	errs := make(chan error, 2)
	quit := make(chan bool)
	go io.Copy(conn, context.Stdin)
	go func() {
		defer close(quit)
		_, err := io.Copy(context.Stdout, conn)
		if err != nil && err != io.EOF {
			errs <- err
		}
	}()
	<-quit
	close(errs)
	return <-errs
}
<commit_msg>provision/docker: ask for size of the terminal and send to the server<commit_after>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"strconv"
	"strings"
	"syscall"

	"code.google.com/p/go.crypto/ssh/terminal"
	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/cmd/tsuru-base"
	"github.com/tsuru/tsuru/errors"
	tsuruIo "github.com/tsuru/tsuru/io"
	"launchpad.net/gnuflag"
)

var httpHeaderRegexp = regexp.MustCompile(`HTTP/.*? (\d+)`)

type moveContainersCmd struct{}

type progressFormatter struct{}

func (progressFormatter) Format(out io.Writer, data []byte) error {
	var logEntry progressLog
	err := json.Unmarshal(data, &logEntry)
	if err != nil {
		return err
	}
	fmt.Fprintf(out, "%s\n", logEntry.Message)
	return nil
}

func (c *moveContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "containers-move",
		Usage:   "containers-move <from host> <to host>",
		Desc:    "Move all containers from one host to another.\nThis command is especially useful for host maintenance.",
		MinArgs: 2,
	}
}

func (c *moveContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL("/docker/containers/move")
	if err != nil {
		return err
	}
	params := map[string]string{
		"from": context.Args[0],
		"to":   context.Args[1],
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

type fixContainersCmd struct{}

func (fixContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:  "fix-containers",
		Usage: "fix-containers",
		Desc:  "Fix containers that are broken in the cluster.",
	}
}

func (fixContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL("/docker/fix-containers")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	return err
}

type moveContainerCmd struct{}

func (c *moveContainerCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "container-move",
		Usage:   "container-move <container id> <to host>",
		Desc:    "Move specified container to another host.",
		MinArgs: 2,
	}
}

func (c *moveContainerCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL(fmt.Sprintf("/docker/container/%s/move", context.Args[0]))
	if err != nil {
		return err
	}
	params := map[string]string{
		"to": context.Args[1],
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

type rebalanceContainersCmd struct {
	tsuru.ConfirmationCommand
	fs  *gnuflag.FlagSet
	dry bool
}

func (c *rebalanceContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "containers-rebalance",
		Usage:   "containers-rebalance [--dry] [-y/--assume-yes]",
		Desc:    "Move containers creating a more even distribution between docker nodes.",
		MinArgs: 0,
	}
}

func (c *rebalanceContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	if !c.dry && !c.Confirm(context, "Are you sure you want to rebalance containers?") {
		return nil
	}
	url, err := cmd.GetURL("/docker/containers/rebalance")
	if err != nil {
		return err
	}
	params := map[string]string{
		"dry": fmt.Sprintf("%t", c.dry),
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

func (c *rebalanceContainersCmd) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		c.fs = c.ConfirmationCommand.Flags()
		c.fs.BoolVar(&c.dry, "dry", false, "Dry run, only shows what would be done")
	}
	return c.fs
}

type sshToContainerCmd struct{}

func (sshToContainerCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "ssh",
		Usage:   "ssh <container-id>",
		Desc:    "Open a SSH shell to the given container.",
		MinArgs: 1,
	}
}

func (sshToContainerCmd) Run(context *cmd.Context, _ *cmd.Client) error {
	var width, height int
	if stdin, ok := context.Stdin.(*os.File); ok {
		fd := int(stdin.Fd())
		if terminal.IsTerminal(fd) {
			width, height, _ = terminal.GetSize(fd)
			oldState, err := terminal.MakeRaw(fd)
			if err != nil {
				return err
			}
			defer terminal.Restore(fd, oldState)
			sigChan := make(chan os.Signal, 2)
			go func(c <-chan os.Signal) {
				if _, ok := <-c; ok {
					terminal.Restore(fd, oldState)
					os.Exit(1)
				}
			}(sigChan)
			signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
		}
	}
	queryString := make(url.Values)
	queryString.Set("width", strconv.Itoa(width))
	queryString.Set("height", strconv.Itoa(height))
	serverURL, err := cmd.GetURL("/docker/ssh/" + context.Args[0] + "?" + queryString.Encode())
	if err != nil {
		return err
	}
	request, err := http.NewRequest("GET", serverURL, nil)
	if err != nil {
		return err
	}
	request.Close = true
	token, err := cmd.ReadToken()
	if err == nil {
		request.Header.Set("Authorization", "bearer "+token)
	}
	parsedURL, _ := url.Parse(serverURL)
	conn, err := net.Dial("tcp", parsedURL.Host)
	if err != nil {
		return err
	}
	defer conn.Close()
	request.Write(conn)
	bytesLimit := 50
	var readStr string
	byteBuffer := make([]byte, 1)
	for i := 0; i < bytesLimit && byteBuffer[0] != '\n'; i++ {
		_, err := conn.Read(byteBuffer)
		if err != nil {
			break
		}
		readStr += string(byteBuffer)
	}
	matches := httpHeaderRegexp.FindAllStringSubmatch(readStr, -1)
	if len(matches) > 0 && len(matches[0]) > 1 {
		code, _ := strconv.Atoi(matches[0][1])
		return &errors.HTTP{
			Code:    code,
			Message: strings.TrimSpace(readStr),
		}
	} else {
		context.Stdout.Write([]byte(readStr))
	}
	errs := make(chan error, 2)
	quit := make(chan bool)
	go io.Copy(conn, context.Stdin)
	go func() {
		defer close(quit)
		_, err := io.Copy(context.Stdout, conn)
		if err != nil && err != io.EOF {
			errs <- err
		}
	}()
	<-quit
	close(errs)
	return <-errs
}
<|endoftext|>


<commit_before>package server_test

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/binary"
	"errors"
	"github.com/WhiteHatCP/seclab-listener/server"
	"testing"
	"time"
)

type nullBackend struct{}

func (b *nullBackend) Open() error {
	return nil
}
func (b *nullBackend) Close() error {
	return nil
}

type errorBackend struct{}

func (b *errorBackend) Open() error {
	return errors.New("open error")
}
func (b *errorBackend) Close() error {
	return errors.New("close error")
}

func getTestInstance() server.Server {
	return server.New([]byte("dismykey"), 10, &nullBackend{})
}

func TestBadSignature(t *testing.T) {
	msg := make([]byte, 41)
	err := getTestInstance().CheckMessage(msg)
	if err == nil || err.Error() != "Incorrect HMAC signature" {
		t.Error("Expected Incorrect HMAC signature, got", err)
	}
}

func TestExpired(t *testing.T) {
	payload := make([]byte, 9)
	mac := hmac.New(sha256.New, []byte("dismykey"))
	mac.Write(payload)
	err := getTestInstance().CheckMessage(mac.Sum(payload))
	if err == nil || err.Error() != "Request expired" {
		t.Error("Expected Request expired, got", err)
	}
}

func TestGoodCheck(t *testing.T) {
	payload := make([]byte, 9)
	payload[0] = 0xff
	now64 := time.Now().Unix()
	binary.BigEndian.PutUint64(payload[1:9], uint64(now64))
	mac := hmac.New(sha256.New, []byte("dismykey"))
	mac.Write(payload)
	message := mac.Sum(payload)
	if err := getTestInstance().CheckMessage(message); err != nil {
		t.Error(err)
	}
}

func TestDispatchUnknown(t *testing.T) {
	_, err := getTestInstance().DispatchRequest(0x69)
	if err == nil || err.Error() != "Unrecognized status byte: 0x69" {
		t.Error("Expected Unrecognized status byte: 0x69, got", err)
	}
}

func TestDispatchOpenError(t *testing.T) {
	s := server.New(nil, 10, &errorBackend{})
	_, err := s.DispatchRequest(0xff)
	if err == nil || err.Error() != "open error" {
		t.Error("Expected open error, got", err)
	}
}

func TestDispatchCloseError(t *testing.T) {
	s := server.New(nil, 10, &errorBackend{})
	_, err := s.DispatchRequest(0x00)
	if err == nil || err.Error() != "close error" {
		t.Error("Expected close error, got", err)
	}
}
<commit_msg>Test correct functionality<commit_after>package server_test

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/binary"
	"errors"
	"github.com/WhiteHatCP/seclab-listener/server"
	"testing"
	"time"
)

type nullBackend struct{}

func (b *nullBackend) Open() error {
	return nil
}
func (b *nullBackend) Close() error {
	return nil
}

type errorBackend struct{}

func (b *errorBackend) Open() error {
	return errors.New("open error")
}
func (b *errorBackend) Close() error {
	return errors.New("close error")
}

func getTestInstance() server.Server {
	return server.New([]byte("dismykey"), 10, &nullBackend{})
}

func TestBadSignature(t *testing.T) {
	msg := make([]byte, 41)
	err := getTestInstance().CheckMessage(msg)
	if err == nil || err.Error() != "Incorrect HMAC signature" {
		t.Error("Expected Incorrect HMAC signature, got", err)
	}
}

func TestExpired(t *testing.T) {
	payload := make([]byte, 9)
	mac := hmac.New(sha256.New, []byte("dismykey"))
	mac.Write(payload)
	err := getTestInstance().CheckMessage(mac.Sum(payload))
	if err == nil || err.Error() != "Request expired" {
		t.Error("Expected Request expired, got", err)
	}
}

func TestGoodCheck(t *testing.T) {
	payload := make([]byte, 9)
	payload[0] = 0xff
	now64 := time.Now().Unix()
	binary.BigEndian.PutUint64(payload[1:9], uint64(now64))
	mac := hmac.New(sha256.New, []byte("dismykey"))
	mac.Write(payload)
	message := mac.Sum(payload)
	if err := getTestInstance().CheckMessage(message); err != nil {
		t.Error(err)
	}
}

func TestDispatchUnknown(t *testing.T) {
	_, err := getTestInstance().DispatchRequest(0x69)
	if err == nil || err.Error() != "Unrecognized status byte: 0x69" {
		t.Error("Expected Unrecognized status byte: 0x69, got", err)
	}
}

func TestDispatchOpenError(t *testing.T) {
	s := server.New(nil, 10, &errorBackend{})
	_, err := s.DispatchRequest(0xff)
	if err == nil || err.Error() != "open error" {
		t.Error("Expected open error, got", err)
	}
}

func TestDispatchCloseError(t *testing.T) {
	s := server.New(nil, 10, &errorBackend{})
	_, err := s.DispatchRequest(0x00)
	if err == nil || err.Error() != "close error" {
		t.Error("Expected close error, got", err)
	}
}

func TestDispatchOpenGood(t *testing.T) {
	resp, err := getTestInstance().DispatchRequest(0xff)
	if err != nil {
		t.Error(err)
	} else if resp != 0xff {
		t.Errorf("Expected 0xff, got 0x%x", resp)
	}
}

func TestDispatchCloseGood(t *testing.T) {
	resp, err := getTestInstance().DispatchRequest(0x00)
	if err != nil {
		t.Error(err)
	} else if resp != 0xff {
		t.Errorf("Expected 0xff, got 0x%x", resp)
	}
}
<|endoftext|>


<commit_before>package auth

/*
 * Implements auth middleware for cention applications.
 * Expects to be running in Gin framework
 */

import (
	wf "c3/osm/webframework"
	"c3/web/controllers"
	"crypto/sha256"
	"encoding/base64"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/cention-mujibur-rahman/gobcache"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/securecookie"
)

const (
	HTTP_UNAUTHORIZE_ACCESS = 401
	HTTP_FORBIDDEN_ACCESS   = 403
	HTTP_FOUND              = 302
)

var (
	hashKey                       = securecookie.GenerateRandomKey(64)
	blockKey                      = securecookie.GenerateRandomKey(32)
	sc                            = securecookie.New(hashKey, blockKey)
	ERROR_USER_PASS_MISMATCH      = errors.New("Username or Password doesnt match!")
	ERROR_USER_PASS_EMPTY         = errors.New("Username or Password is empty!")
	ERROR_CACHE_MISSED            = errors.New("Cache missed somehow!")
	ERROR_ON_SECURECOOKIE_HASHKEY = errors.New("HashKey doesn't match with secureCookie")
	ERROR_COOKIE_NOT_FOUND        = errors.New("Cookie: cention-suiteSSID=? not found")
	ERROR_WF_USER_NULL            = errors.New("webframework user is null")
	ERROR_MEMCACHE_FAILED         = errors.New("Sessiond not running")
)

var (
	sessiond = gobcache.NewCache("localhost:11311")
)

type AuthCookieManager struct {
	UserId        int
	LastLoginTime int64
	LoggedIn      bool
}

func checkingMemcache() bool {
	conn, err := net.Dial("tcp", "localhost:11311")
	if err != nil {
		log.Println("Sessiond Server is not running! ", err)
		return false
	}
	defer conn.Close()
	return true
}

func getCookieHashKey(ctx *gin.Context) (string, error) {
	cookie, err := ctx.Request.Cookie("cention-suiteSSID")
	if err != nil {
		log.Println("getCookieHashKey(): Cookie is empty - ", err)
		return "", err
	}
	if cookie != nil && cookie.Value == "" && cookie.Value == "guest" {
		return "", ERROR_CACHE_MISSED
	}
	return cookie.Value, nil
}

func decodeCookie(ctx *gin.Context) (string, error) {
	cookie, err := getCookieHashKey(ctx)
	if err != nil {
		return "", err
	}
	if cookie != "" && cookie != "guest" {
		return cookie, nil
	}
	return "", ERROR_COOKIE_NOT_FOUND
}

func getCurrentSession(v []byte) (int, int, bool, error) {
	sv := string(v)
	sValue := strings.Split(sv, "/")
	if len(sValue) != 3 {
		return 0, 0, false, ERROR_CACHE_MISSED
	}
	uid, err := strconv.Atoi(sValue[0])
	if err != nil {
		log.Printf("Error on Uid conversion: %v", err)
		return 0, 0, false, err
	}
	ts, err := strconv.Atoi(sValue[1])
	if err != nil {
		log.Printf("Error on timestampLastLogin conversion: %v", err)
		return 0, 0, false, err
	}
	currentlyLoggedIn, err := strconv.ParseBool(sValue[2])
	if err != nil {
		log.Printf("Error on currentlyLoggedIn conversion: %v", err)
		return 0, 0, false, err
	}
	return uid, ts, currentlyLoggedIn, nil
}

func fetchFromCache(key string) error {
	skey := "Session_" + key
	sItems, err := sessiond.GetRawFromMemcache(skey)
	if err != nil {
		log.Println("[GetRawFromMemcache] key `Session` is empty!")
		return err
	}
	if sItems != nil {
		uid, timestamp, currentlyLogedin, err := getCurrentSession(sItems.Value)
		if err != nil {
			return err
		}
		//Mujibur: timestamp, thinking how to use it?
		_ = timestamp
		if uid != 0 && currentlyLogedin {
			return nil
		}
	}
	return ERROR_CACHE_MISSED
}

func CheckOrCreateAuthCookie(ctx *gin.Context) error {
	ssid, err := decodeCookie(ctx)
	if err != nil {
		err := createNewAuthCookie(ctx)
		if err != nil {
			return err
		}
		return nil
	}
	user := ctx.Request.FormValue("username")
	pass := ctx.Request.FormValue("password")
	if user == "" && pass == "" {
		if checkingMemcache() {
			if err = fetchFromCache(ssid); err != nil {
				return err
			}
			return nil
		}
		return ERROR_USER_PASS_EMPTY
	} else {
		log.Println("!!-- Setting cookie informations to memcache. First time login.")
		wfUser, err := validateUser(user, pass)
		if err != nil {
			log.Println("Error on CheckOrCreateAuthCookie() - validateUser: ", err)
			return err
		}
		if wfUser != nil {
			lastLoginTime := time.Now().Unix()
			if checkingMemcache() {
				sValue := fmt.Sprintf("%v/%v/%v", wfUser.Id, lastLoginTime, true)
				if err = saveToSessiondCache(ssid, sValue); err != nil {
					return err
				}
				if err = saveUserIdToCache(wfUser.Id, ssid); err != nil {
					return err
				}
				log.Printf("CentionAuth: User `%s` just now Logged In", wfUser.Username)
				return nil
			} else {
				return ERROR_MEMCACHE_FAILED
			}
		}
	}
	return ERROR_WF_USER_NULL
}

func saveUserIdToCache(key int, value string) error {
	sKey := fmt.Sprintf("user/%d", key)
	if err := sessiond.SetRawToMemcache(sKey, value); err != nil {
		log.Println("[`SetRawToMemcache`] Error on saving:", err)
		return err
	}
	return nil
}

func saveToSessiondCache(key, value string) error {
	sKey := "Session_" + key
	if err := sessiond.SetRawToMemcache(sKey, value); err != nil {
		log.Println("[`SetRawToMemcache`] Error on saving:", err)
		return err
	}
	return nil
}

func validateUser(user, pass string) (*wf.User, error) {
	wu, err := wf.QueryUser_byLogin(user)
	if err != nil {
		return nil, err
	}
	if wu != nil {
		if wu.Active && wu.Password == encodePassword(pass) {
			return wu, nil
		}
	}
	return nil, ERROR_USER_PASS_MISMATCH
}
func encodePassword(p string) string {
	ep := sha256.New()
	_, err := ep.Write([]byte(p))
	if err != nil {
		log.Println("encodePassword() - Error on Sha256: ", err)
		return ""
	}
	return base64.StdEncoding.EncodeToString(ep.Sum(nil))
}
func createNewAuthCookie(ctx *gin.Context) error {
	value := map[string]interface{}{
		"cookie-set-date": time.Now().Unix(),
	}
	encoded, err := sc.Encode("cention-suiteSSID", value)
	if err != nil {
		log.Printf("createNewAuthCookie(): Error %v, creating `guest` cookie", err)
		cookie := fmt.Sprintf("cention-suiteSSID=%s; Path=/", "guest")
		ctx.Writer.Header().Add("Set-Cookie", cookie)
		return err
	}
	cookie := fmt.Sprintf("cention-suiteSSID=%s; Path=/", encoded)
	ctx.Writer.Header().Add("Set-Cookie", cookie)
	return nil
}
func CheckAuthCookie(ctx *gin.Context) (bool, error) {
	cookie, err := decodeCookie(ctx)
	if err != nil {
		return false, err
	}
	ok, err := validateByBrowserCookie(cookie)
	if err != nil {
		return false, err
	}
	if !ok {
		return false, err
	}
	return true, nil
}

func fetchFromCacheWithValue(key string) (int, int, bool, error) {
	skey := "Session_" + key
	sItems, err := sessiond.GetRawFromMemcache(skey)
	if err != nil {
		log.Println("[GetRawFromMemcache] key `Session` is empty!")
		return 0, 0, false, err
	}
	if sItems != nil {
		uid, timestamp, currentlyLogedin, err := getCurrentSession(sItems.Value)
		if err != nil {
			return 0, 0, false, err
		}
		if uid != 0 && currentlyLogedin {
			return uid, timestamp, currentlyLogedin, nil
		}
	}
	return 0, 0, false, ERROR_CACHE_MISSED
}

func validateByBrowserCookie(ssid string) (bool, error) {
	if checkingMemcache() {
		uid, _, currentlyLogedin, err := fetchFromCacheWithValue(ssid)
		if err != nil {
			return false, err
		}
		if err := updateTimeStampToCache(ssid, uid, currentlyLogedin); err != nil {
			log.Printf("Error on validateByBrowserCookie(): %v", err)
			return false, err
		}
		log.Printf("CentionAuth: Cookie has verified with this info: %v", uid)
		return true, nil
	}
	return false, ERROR_MEMCACHE_FAILED
}

func destroyAuthCookie(ctx *gin.Context) error {
	ssid, err := decodeCookie(ctx)
	if err != nil {
		return err
	}
	if checkingMemcache() {
		uid, _, _, err := fetchFromCacheWithValue(ssid)
		if err != nil {
			return err
		}
		if err := updateTimeStampToCache(ssid, uid, false); err != nil {
			log.Printf("Error on validateByBrowserCookie(): %v", err)
			return err
		}
		return nil
	}
	return ERROR_MEMCACHE_FAILED
}
func Logout(ctx *gin.Context) error {
	return destroyAuthCookie(ctx)
}

func fetchCookieFromRequest(r *http.Request) (string, error) {
	cookie, err := r.Cookie("cention-suiteSSID")
	if err != nil {
		return "", err
	}
	return cookie.Value, nil
}
func GetWebframeworkUserFromRequest(r *http.Request) int {
	ssid, err := fetchCookieFromRequest(r)
	if err != nil {
		log.Printf("Error on getting SSID: %v", err)
		return 0
	}
	if ssid == "" {
		return 0
	}
	if checkingMemcache() {
		uid, _, currentlyLogedin, err := fetchFromCacheWithValue(ssid)
		if err != nil {
			log.Println("Error on fetchFromCacheWithValue(): ", err)
			return 0
		}
		if !currentlyLogedin {
			return 0
		}
		//Update timestamp for every request
		if err := updateTimeStampToCache(ssid, uid, currentlyLogedin); err != nil {
			log.Printf("Error on %v", err)
			return 0
		}
		return uid
	}
	return 0
}

func updateTimeStampToCache(ssid string, uid int, loginStatus bool) error {
	lastTimeGetRequest := time.Now().Unix()
	svalue := fmt.Sprintf("%v/%v/%v", uid, lastTimeGetRequest, loginStatus)
	if err := saveToSessiondCache(ssid, svalue); err != nil {
		return err
	}
	return nil
}
func Middleware() func(*gin.Context) {
	return func(ctx *gin.Context) {
		if strings.HasPrefix(ctx.Request.RequestURI, "/debug/pprof/") {
			ctx.Next()
			return
		}
		wfUserId := GetWebframeworkUserFromRequest(ctx.Request)
		if wfUserId == 0 {
			ctx.AbortWithStatus(HTTP_UNAUTHORIZE_ACCESS)
			return
		}
		currUser := controllers.FetchUserObject(wfUserId)
		ctx.Keys = make(map[string]interface{})
		ctx.Keys["loggedInUser"] = currUser
		ctx.Next()
	}
}
<commit_msg>Reports: needs to get the users lastlogin, lastlogout<commit_after>package auth

/*
 * Implements auth middleware for cention applications.
 * Expects to be running in Gin framework
 */

import (
	wf "c3/osm/webframework"
	"c3/osm/workflow"
	"c3/web/controllers"
	"crypto/sha256"
	"encoding/base64"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/cention-mujibur-rahman/gobcache"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/securecookie"
)

const (
	HTTP_UNAUTHORIZE_ACCESS = 401
	HTTP_FORBIDDEN_ACCESS   = 403
	HTTP_FOUND              = 302
)

var (
	hashKey                       = securecookie.GenerateRandomKey(64)
	blockKey                      = securecookie.GenerateRandomKey(32)
	sc                            = securecookie.New(hashKey, blockKey)
	ERROR_USER_PASS_MISMATCH      = errors.New("Username or Password doesnt match!")
	ERROR_USER_PASS_EMPTY         = errors.New("Username or Password is empty!")
	ERROR_CACHE_MISSED            = errors.New("Cache missed somehow!")
	ERROR_ON_SECURECOOKIE_HASHKEY = errors.New("HashKey doesn't match with secureCookie")
	ERROR_COOKIE_NOT_FOUND        = errors.New("Cookie: cention-suiteSSID=? not found")
	ERROR_WF_USER_NULL            = errors.New("webframework user is null")
	ERROR_MEMCACHE_FAILED         = errors.New("Sessiond not running")
)

var (
	sessiond = gobcache.NewCache("localhost:11311")
)

type AuthCookieManager struct {
	UserId        int
	LastLoginTime int64
	LoggedIn      bool
}

func checkingMemcache() bool {
	conn, err := net.Dial("tcp", "localhost:11311")
	if err != nil {
		log.Println("Sessiond Server is not running! ", err)
		return false
	}
	defer conn.Close()
	return true
}

func getCookieHashKey(ctx *gin.Context) (string, error) {
	cookie, err := ctx.Request.Cookie("cention-suiteSSID")
	if err != nil {
		log.Println("getCookieHashKey(): Cookie is empty - ", err)
		return "", err
	}
	if cookie != nil && cookie.Value == "" && cookie.Value == "guest" {
		return "", ERROR_CACHE_MISSED
	}
	return cookie.Value, nil
}

func decodeCookie(ctx *gin.Context) (string, error) {
	cookie, err := getCookieHashKey(ctx)
	if err != nil {
		return "", err
	}
	if cookie != "" && cookie != "guest" {
		return cookie, nil
	}
	return "", ERROR_COOKIE_NOT_FOUND
}

func getCurrentSession(v []byte) (int, int, bool, error) {
	sv := string(v)
	sValue := strings.Split(sv, "/")
	if len(sValue) != 3 {
		return 0, 0, false, ERROR_CACHE_MISSED
	}
	uid, err := strconv.Atoi(sValue[0])
	if err != nil {
		log.Printf("Error on Uid conversion: %v", err)
		return 0, 0, false, err
	}
	ts, err := strconv.Atoi(sValue[1])
	if err != nil {
		log.Printf("Error on timestampLastLogin conversion: %v", err)
		return 0, 0, false, err
	}
	currentlyLoggedIn, err := strconv.ParseBool(sValue[2])
	if err != nil {
		log.Printf("Error on currentlyLoggedIn conversion: %v", err)
		return 0, 0, false, err
	}
	return uid, ts, currentlyLoggedIn, nil
}

func fetchFromCache(key string) error {
	skey := "Session_" + key
	sItems, err := sessiond.GetRawFromMemcache(skey)
	if err != nil {
		log.Println("[GetRawFromMemcache] key `Session` is empty!")
		return err
	}
	if sItems != nil {
		uid, _, currentlyLogedin, err := getCurrentSession(sItems.Value)
		if err != nil {
			return err
		}
		if uid != 0 && currentlyLogedin {
			return nil
		}
	}
	return ERROR_CACHE_MISSED
}

func CheckOrCreateAuthCookie(ctx *gin.Context) error {
	ssid, err := decodeCookie(ctx)
	if err != nil {
		err := createNewAuthCookie(ctx)
		if err != nil {
			return err
		}
		return nil
	}
	user := ctx.Request.FormValue("username")
	pass := ctx.Request.FormValue("password")
	if user == "" && pass == "" {
		if checkingMemcache() {
			if err = fetchFromCache(ssid); err != nil {
				return err
			}
			return nil
		}
		return ERROR_USER_PASS_EMPTY
	} else {
		log.Println("!!-- Setting cookie informations to memcache. First time login.")
		wfUser, err := validateUser(user, pass)
		if err != nil {
			log.Println("Error on CheckOrCreateAuthCookie() - validateUser: ", err)
			return err
		}
		if wfUser != nil {
			lastLoginTime := time.Now().Unix()
			if checkingMemcache() {
				sValue := fmt.Sprintf("%v/%v/%v", wfUser.Id, lastLoginTime, true)
				if err = saveToSessiondCache(ssid, sValue); err != nil {
					return err
				}
				if err = saveUserIdToCache(wfUser.Id, ssid); err != nil {
					return err
				}
				updateUserCurrentLoginIn(wfUser.Id)
				log.Printf("CentionAuth: User `%s` just now Logged In", wfUser.Username)
				return nil
			} else {
				return ERROR_MEMCACHE_FAILED
			}
		}
	}
	return ERROR_WF_USER_NULL
}
func updateUserCurrentLoginIn(wfUId int) {
	user, err := workflow.QueryUser_byWebframeworkUser(wfUId)
	if err != nil {
		log.Println("Error QueryUser_byWebframeworkUser: ", err)
	}
	user.SetTimestampLastLogin(time.Now().Unix())
	user.SetCurrentlyLoggedIn(true)
	if err := user.Save(); err != nil {
		log.Println("Error on Save: ", err)
	}
}
func updateUserCurrentLoginOut(wfUId int) {
	user, err := workflow.QueryUser_byWebframeworkUser(wfUId)
	if err != nil {
		log.Println("Error QueryUser_byWebframeworkUser: ", err)
	}
	user.SetTimestampLastLogout(time.Now().Unix())
	user.SetCurrentlyLoggedIn(false)
	if err := user.Save(); err != nil {
		log.Println("Error on Save: ", err)
	}
}
func saveUserIdToCache(key int, value string) error {
	sKey := fmt.Sprintf("user/%d", key)
	if err := sessiond.SetRawToMemcache(sKey, value); err != nil {
		log.Println("[`SetRawToMemcache`] Error on saving:", err)
		return err
	}
	return nil
}

func saveToSessiondCache(key, value string) error {
	sKey := "Session_" + key
	if err := sessiond.SetRawToMemcache(sKey, value); err != nil {
		log.Println("[`SetRawToMemcache`] Error on saving:", err)
		return err
	}
	return nil
}

func validateUser(user, pass string) (*wf.User, error) {
	wu, err := wf.QueryUser_byLogin(user)
	if err != nil {
		return nil, err
	}
	if wu != nil {
		if wu.Active && wu.Password == encodePassword(pass) {
			return wu, nil
		}
	}
	return nil, ERROR_USER_PASS_MISMATCH
}
func encodePassword(p string) string {
	ep := sha256.New()
	_, err := ep.Write([]byte(p))
	if err != nil {
		log.Println("encodePassword() - Error on Sha256: ", err)
		return ""
	}
	return base64.StdEncoding.EncodeToString(ep.Sum(nil))
}
func createNewAuthCookie(ctx *gin.Context) error {
	value := map[string]interface{}{
		"cookie-set-date": time.Now().Unix(),
	}
	encoded, err := sc.Encode("cention-suiteSSID", value)
	if err != nil {
		log.Printf("createNewAuthCookie(): Error %v, creating `guest` cookie", err)
		cookie := fmt.Sprintf("cention-suiteSSID=%s; Path=/", "guest")
		ctx.Writer.Header().Add("Set-Cookie", cookie)
		return err
	}
	cookie := fmt.Sprintf("cention-suiteSSID=%s; Path=/", encoded)
	ctx.Writer.Header().Add("Set-Cookie", cookie)
	return nil
}
func CheckAuthCookie(ctx *gin.Context) (bool, error) {
	cookie, err := decodeCookie(ctx)
	if err != nil {
		return false, err
	}
	ok, err := validateByBrowserCookie(cookie)
	if err != nil {
		return false, err
	}
	if !ok {
		return false, err
	}
	return true, nil
}

func fetchFromCacheWithValue(key string) (int, int, bool, error) {
	skey := "Session_" + key
	sItems, err := sessiond.GetRawFromMemcache(skey)
	if err != nil {
		log.Println("[GetRawFromMemcache] key `Session` is empty!")
		return 0, 0, false, err
	}
	if sItems != nil {
		uid, timestamp, currentlyLogedin, err := getCurrentSession(sItems.Value)
		if err != nil {
			return 0, 0, false, err
		}
		if uid != 0 && !currentlyLogedin {
			return uid, timestamp, !currentlyLogedin, nil
		}
		if uid != 0 && currentlyLogedin {
			return uid, timestamp, currentlyLogedin, nil
		}
	}
	return 0, 0, false, ERROR_CACHE_MISSED
}

func validateByBrowserCookie(ssid string) (bool, error) {
	if checkingMemcache() {
		uid, _, currentlyLogedin, err := fetchFromCacheWithValue(ssid)
		if err != nil {
			return false, err
		}
		if err := updateTimeStampToCache(ssid, uid, currentlyLogedin); err != nil {
			log.Printf("Error on validateByBrowserCookie(): %v", err)
			return false, err
		}
		log.Printf("CentionAuth: Cookie has verified with this info: %v", uid)
		return true, nil
	}
	return false, ERROR_MEMCACHE_FAILED
}

func destroyAuthCookie(ctx *gin.Context) error {
	ssid, err := decodeCookie(ctx)
	if err != nil {
		return err
	}
	if checkingMemcache() {
		uid, _, _, err := fetchFromCacheWithValue(ssid)
		if err != nil {
			return err
		}
		if err := updateTimeStampToCache(ssid, uid, false); err != nil {
			log.Printf("Error on validateByBrowserCookie(): %v", err)
			return err
		}
		updateUserCurrentLoginOut(uid)
		return nil
	}
	return ERROR_MEMCACHE_FAILED
}
func Logout(ctx *gin.Context) error {
	return destroyAuthCookie(ctx)
}

func fetchCookieFromRequest(r *http.Request) (string, error) {
	cookie, err := r.Cookie("cention-suiteSSID")
	if err != nil {
		return "", err
	}
	return cookie.Value, nil
}
func GetWebframeworkUserFromRequest(r *http.Request) int {
	ssid, err := fetchCookieFromRequest(r)
	if err != nil {
		log.Printf("Error on getting SSID: %v", err)
		return 0
	}
	if ssid == "" {
		return 0
	}
	if checkingMemcache() {
		uid, _, currentlyLogedin, err := fetchFromCacheWithValue(ssid)
		if err != nil {
			log.Println("Error on fetchFromCacheWithValue(): ", err)
			return 0
		}
		if !currentlyLogedin {
			return 0
		}
		//Update timestamp for every request
		if err := updateTimeStampToCache(ssid, uid, currentlyLogedin); err != nil {
			log.Printf("Error on %v", err)
			return 0
		}
		return uid
	}
	return 0
}

func updateTimeStampToCache(ssid string, uid int, loginStatus bool) error {
	lastTimeGetRequest := time.Now().Unix()
	svalue := fmt.Sprintf("%v/%v/%v", uid, lastTimeGetRequest, loginStatus)
	if err := saveToSessiondCache(ssid, svalue); err != nil {
		return err
	}
	return nil
}
func Middleware() func(*gin.Context) {
	return func(ctx *gin.Context) {
		if strings.HasPrefix(ctx.Request.RequestURI, "/debug/pprof/") {
			ctx.Next()
			return
		}
		wfUserId := GetWebframeworkUserFromRequest(ctx.Request)
		if wfUserId == 0 {
			ctx.AbortWithStatus(HTTP_UNAUTHORIZE_ACCESS)
			return
		}
		currUser := controllers.FetchUserObject(wfUserId)
		ctx.Keys = make(map[string]interface{})
		ctx.Keys["loggedInUser"] = currUser
		ctx.Next()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path"
	"net/http"
	"io"

	"github.com/Sirupsen/logrus"
	"github.com/samalba/dockerclient"
)

// instance of DockerClient allowing for making calls to the docker daemon
// remote API
var dockerClient *dockerclient.DockerClient

func main() {

	// init docker client object
	var err error
	dockerClient, err = dockerclient.NewDockerClient("unix:///var/run/docker.sock", nil)
	if err != nil {
		logrus.Fatal(err.Error())
	}

	// get the version of the docker daemon so we can be sure the corresponding
	// docker client is installed and install it if necessary
	version, err := dockerClient.Version()
	if err != nil {
		logrus.Fatal(err.Error())
	}
	dockerDaemonVersion := version.Version

	// name of docker binary that is needed
	dockerBinaryName := "docker-" + dockerDaemonVersion
	logrus.Println("looking for docker binary named:", dockerBinaryName)

	filename := path.Join("/bin", dockerBinaryName)

	if _, err := os.Stat(filename); os.IsNotExist(err) {

		logrus.Println("docker binary (version " + dockerDaemonVersion + ") not found.")
		logrus.Println("downloading", dockerBinaryName, "...")

		out, err := os.Create(filename)
		if err != nil {
			logrus.Fatal(err.Error())
		}
		defer out.Close()
		resp, err := http.Get("https://get.docker.com/builds/Linux/x86_64/docker-" + dockerDaemonVersion)
		if err != nil {
			logrus.Fatal(err.Error())
		}
		defer resp.Body.Close()

		_, err = io.Copy(out, resp.Body)
		if err != nil {
			logrus.Fatal(err.Error())
		}

		err = os.Chmod(filename, 0700)
		if err != nil {
			logrus.Fatal(err.Error())
		}
    }
}
<commit_msg>Get the docker client from the tgz file<commit_after>package main

import (
	"os"
	"path"
	"net/http"
	"io"
	"archive/tar"
	"compress/gzip"
	"github.com/Sirupsen/logrus"
	"github.com/samalba/dockerclient"
)

// instance of DockerClient allowing for making calls to the docker daemon
// remote API
var dockerClient *dockerclient.DockerClient

func main() {

	// init docker client object
	var err error
	dockerClient, err = dockerclient.NewDockerClient("unix:///var/run/docker.sock", nil)
	if err != nil {
		logrus.Fatal(err.Error())
	}

	// get the version of the docker daemon so we can be sure the corresponding
	// docker client is installed and install it if necessary
	version, err := dockerClient.Version()
	if err != nil {
		logrus.Fatal(err.Error())
	}
	dockerDaemonVersion := version.Version

	// name of docker binary that is needed
	dockerBinaryName := "docker-" + dockerDaemonVersion
	logrus.Println("looking for docker binary named:", dockerBinaryName)

        filename := path.Join("/bin", dockerBinaryName)

	if _, err := os.Stat(filename); os.IsNotExist(err) {

		logrus.Println("docker binary (version " + dockerDaemonVersion + ") not found.")
		logrus.Println("downloading", dockerBinaryName, "...")

		out, err := os.Create(filename)
		if err != nil {
			logrus.Fatal(err.Error())
		}
		defer out.Close()
		resp, err := http.Get("https://get.docker.com/builds/Linux/x86_64/docker-" + dockerDaemonVersion + ".tgz")
		if err != nil {
			logrus.Fatal(err.Error())
		}
		defer resp.Body.Close()

		gr, err := gzip.NewReader(resp.Body)
                defer gr.Close()
                if err != nil {
                       logrus.Fatal(err.Error())
                }

                tr := tar.NewReader(gr)
                for {
                        hdr, err := tr.Next()
                        if err == io.EOF {
                               break
                        }
                        if err != nil {
                               logrus.Fatal(err.Error())
                        }

                        if hdr.Typeflag == tar.TypeReg && hdr.Name == "docker/docker" {
                                _, err = io.Copy(out, tr)
                                if err != nil {
                                        logrus.Fatal(err.Error())
		                }
                                break
                        }
                        logrus.Println("not yet")
                }

		err = os.Chmod(filename, 0700)
		if err != nil {
			logrus.Fatal(err.Error())
		}
    }
}
<|endoftext|>


<commit_before>package server

import (
	"github.com/privacybydesign/irmago"
	sseclient "github.com/sietseringers/go-sse"
	"strings"
	"time"
)

const pollInterval = 1000 * time.Millisecond

func WaitStatus(transport *irma.HTTPTransport, initialStatus Status, statuschan chan Status, errorchan chan error) {
	if err := subscribeSSE(transport, statuschan, errorchan); err != nil {
		go poll(transport, initialStatus, statuschan, errorchan)
	}
}

func WaitStatusChanged(transport *irma.HTTPTransport, initialStatus Status, statuschan chan Status, errorchan chan error) {
	if err := subscribeSSE(transport, statuschan, errorchan); err != nil {
		go pollUntilChange(transport, initialStatus, statuschan, errorchan)
	}
}

// Start listening for server-sent events
func subscribeSSE(transport *irma.HTTPTransport, statuschan chan Status, errorchan chan error) error {

	events := make(chan *sseclient.Event)
	go func() {
		for {
			if e := <-events; e != nil && e.Type != "open" {
				status := Status(strings.Trim(string(e.Data), `"`))
				statuschan <- status
				if status.Finished() {
					errorchan <- nil
					return
				}
			}
		}
	}()

	err := sseclient.Notify(nil, transport.Server+"statusevents", true, events)
	if err != nil {
		close(events)
	}
	return err
}

// poll recursively polls the session status until a final status is received.
func poll(transport *irma.HTTPTransport, initialStatus Status, statuschan chan Status, errorchan chan error) {
	go func() {
		status := initialStatus
		for {
			statuschanPolling := make(chan Status)
			errorchanPolling := make(chan error)
			go pollUntilChange(transport, status, statuschanPolling, errorchanPolling)
			select {
			case status = <-statuschanPolling:
				statuschan <- status
				if status.Finished() {
					errorchan <- nil
					return
				}
				break
			case err := <-errorchanPolling:
				errorchan <- err
				return
			}
		}
	}()
}

func pollUntilChange(transport *irma.HTTPTransport, initialStatus Status, statuschan chan Status, errorchan chan error) {
	// First we wait
	<-time.NewTimer(pollInterval).C

	// Get session status
	var s string
	if err := transport.Get("status", &s); err != nil {
		errorchan <- err
		return
	}
	status := Status(strings.Trim(s, `"`))

	// report if status changed
	if status != initialStatus {
		statuschan <- status
		errorchan <- nil
		return
	}

	go pollUntilChange(transport, status, statuschan, errorchan)
}
<commit_msg>Cancel sse channel when closing it prematurely<commit_after>package server

import (
	"context"
	"github.com/privacybydesign/irmago"
	sseclient "github.com/sietseringers/go-sse"
	"strings"
	"time"
)

const pollInterval = 1000 * time.Millisecond

func WaitStatus(transport *irma.HTTPTransport, initialStatus Status, statuschan chan Status, errorchan chan error) {
	if err := subscribeSSE(transport, statuschan, errorchan, false); err != nil {
		go poll(transport, initialStatus, statuschan, errorchan)
	}
}

func WaitStatusChanged(transport *irma.HTTPTransport, initialStatus Status, statuschan chan Status, errorchan chan error) {
	if err := subscribeSSE(transport, statuschan, errorchan, true); err != nil {
		go pollUntilChange(transport, initialStatus, statuschan, errorchan)
	}
}

// Start listening for server-sent events
func subscribeSSE(transport *irma.HTTPTransport, statuschan chan Status, errorchan chan error, untilNextOnly bool) error {
	ctx, cancel := context.WithCancel(context.Background())

	events := make(chan *sseclient.Event)
	cancelled := false
	go func() {
		for {
			e := <-events
			if e != nil && e.Type != "open" {
				status := Status(strings.Trim(string(e.Data), `"`))
				statuschan <- status
				if untilNextOnly || status.Finished() {
					errorchan <- nil
					cancelled = true
					cancel()
					return
				}
			}
		}
	}()

	err := sseclient.Notify(ctx, transport.Server+"statusevents", true, events)
	if !cancelled {
		close(events)
		return err
	}
	return nil
}

// poll recursively polls the session status until a final status is received.
func poll(transport *irma.HTTPTransport, initialStatus Status, statuschan chan Status, errorchan chan error) {
	go func() {
		status := initialStatus
		for {
			statuschanPolling := make(chan Status)
			errorchanPolling := make(chan error)
			go pollUntilChange(transport, status, statuschanPolling, errorchanPolling)
			select {
			case status = <-statuschanPolling:
				statuschan <- status
				if status.Finished() {
					errorchan <- nil
					return
				}
				break
			case err := <-errorchanPolling:
				errorchan <- err
				return
			}
		}
	}()
}

func pollUntilChange(transport *irma.HTTPTransport, initialStatus Status, statuschan chan Status, errorchan chan error) {
	// First we wait
	<-time.NewTimer(pollInterval).C

	// Get session status
	var s string
	if err := transport.Get("status", &s); err != nil {
		errorchan <- err
		return
	}
	status := Status(strings.Trim(s, `"`))

	// report if status changed
	if status != initialStatus {
		statuschan <- status
		errorchan <- nil
		return
	}

	go pollUntilChange(transport, status, statuschan, errorchan)
}
<|endoftext|>


<commit_before>package html

import (
	"html/template"
	"time"

	"github.com/chrisolsen/ae"
	"github.com/russross/blackfriday"
	"google.golang.org/appengine/datastore"
)

// CSS prevents any custom embedded styles from being encoded to html safe values
func CSS(s string) template.CSS {
	return template.CSS(s)
}

// Preview returns a preview of the string
func Preview(size int, val string) string {
	if len(val) <= size {
		return val
	}
	return val[:size-1] + "..."
}

// Markdown converts text in the markdown syntax to html
func Markdown(input string) interface{} {
	out := string(blackfriday.MarkdownCommon([]byte(input)))
	return template.HTML(out)
}

// Add adds the numbers
func Add(a, b int) int {
	return a + b
}

// EncodeKey encodes a datastore key
func EncodeKey(data interface{}) string {
	switch data.(type) {
	case ae.Model:
		return data.(ae.Model).Key.Encode()
	case *datastore.Key:
		return data.(*datastore.Key).Encode()
	default:
		return ""
	}
}

// Checked returns the checked attribute for positive values.
// 	<input type="checkbox" {{IsAdmin | checked}}> => <input type="checkbox" checked="checked">
func Checked(checked bool) template.HTMLAttr {
	if checked {
		return template.HTMLAttr("checked")
	}
	return ""
}

func Selected(selected bool) template.HTMLAttr {
	if selected {
		return template.HTMLAttr("selected")
	}
	return ""
}

// Disabled returns the checked attribute for positive values.
// 	<button type="submit" {{HasError | disabled}}>Save</button> => <button type="submit" disabled="">Save</button>
// 	or
// 	<button type="submit" {{ValidationError | disabled}}>Save</button> => <button type="submit" disabled="">Save</button>
func Disabled(err interface{}) template.HTMLAttr {
	d := template.HTMLAttr("disabled")
	switch err.(type) {
	case string:
		if len(err.(string)) == 0 {
			return ""
		}
		return d
	case error:
		return d
	default:
		return ""
	}
}

// Show returns an empty style attr or display:none
//
 =>
some hidden text

func Show(display bool) template.CSS {
	if display {
		return template.CSS("")
	}
	return template.CSS("display:none;")
}

func Hide(display bool) template.CSS {
	return Show(!display)
}

// KeyEqual allow for *datastore.Key comparison
func KeyEqual(a, b *datastore.Key) bool {
	return a.Equal(b)
}

// Timestamp formats the time to the RFC3339 layout
func Timestamp(d time.Time) string {
	return d.Format(time.RFC3339)
}
<commit_msg>add some common template helpers<commit_after>package html

import (
	"html/template"
	"time"

	"github.com/chrisolsen/ae"
	"github.com/russross/blackfriday"
	"google.golang.org/appengine/datastore"
)

// CSS prevents any custom embedded styles from being encoded to html safe values
func CSS(s string) template.CSS {
	return template.CSS(s)
}

// Preview returns a preview of the string
func Preview(size int, val string) string {
	if len(val) <= size {
		return val
	}
	return val[:size-1] + "..."
}

// Markdown converts text in the markdown syntax to html
func Markdown(input string) interface{} {
	out := string(blackfriday.MarkdownCommon([]byte(input)))
	return template.HTML(out)
}

// Add adds the numbers
func Add(a, b int) int {
	return a + b
}

// EncodeKey encodes a datastore key
func EncodeKey(data interface{}) string {
	switch data.(type) {
	case ae.Model:
		return data.(ae.Model).Key.Encode()
	case *datastore.Key:
		key := data.(*datastore.Key)
		if key == nil {
			return ""
		}
		return key.Encode()
	default:
		return ""
	}
}

// EncodeParentKey encodes the key's parent
func EncodeParentKey(key *datastore.Key) string {
	return key.Parent().Encode()
}

// Checked returns the checked attribute for positive values.
// 	<input type="checkbox" {{IsAdmin | checked}}> => <input type="checkbox" checked="checked">
func Checked(checked interface{}) template.HTMLAttr {
	switch checked.(type) {
	case bool:
		if checked.(bool) {
			return template.HTMLAttr("checked")
		}
	}
	return ""
}

func Selected(selected bool) template.HTMLAttr {
	if selected {
		return template.HTMLAttr("selected")
	}
	return ""
}

// Disabled returns the checked attribute for positive values.
// 	<button type="submit" {{HasError | disabled}}>Save</button> => <button type="submit" disabled="">Save</button>
// 	or
// 	<button type="submit" {{ValidationError | disabled}}>Save</button> => <button type="submit" disabled="">Save</button>
func Disabled(obj interface{}) template.HTMLAttr {
	d := template.HTMLAttr("disabled")
	switch obj.(type) {
	case string:
		if len(obj.(string)) == 0 {
			return ""
		}
		return d
	case bool:
		if obj.(bool) {
			return d
		}
		return ""
	case error:
		return d
	default:
		return ""
	}
}

// Show returns an empty style attr or display:none
//
 =>
some hidden text

func Show(display bool) template.CSS {
	if display {
		return template.CSS("")
	}
	return template.CSS("display:none;")
}

func Hide(display bool) template.CSS {
	return Show(!display)
}

// KeyEqual allow for *datastore.Key comparison
func KeyEqual(a, b *datastore.Key) bool {
	return a.Equal(b)
}

// Timestamp formats the time to the RFC3339 layout
func Timestamp(d time.Time) string {
	return d.Format(time.RFC3339)
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/base64"
	"encoding/json"
)

// Cluster represents high-level information about a LXD cluster.
//
// swagger:model
//
// API extension: clustering
type Cluster struct {
	// Name of the cluster member answering the request
	// Example: lxd01
	ServerName string `json:"server_name" yaml:"server_name"`

	// Whether clustering is enabled
	// Example: true
	Enabled bool `json:"enabled" yaml:"enabled"`

	// List of member configuration keys (used during join)
	// Example: []
	//
	// API extension: clustering_join
	MemberConfig []ClusterMemberConfigKey `json:"member_config" yaml:"member_config"`
}

// ClusterMemberConfigKey represents a single config key that a new member of
// the cluster is required to provide when joining.
//
// The Value field is empty when getting clustering information with GET
// /1.0/cluster, and should be filled by the joining node when performing a PUT
// /1.0/cluster join request.
//
// swagger:model
//
// API extension: clustering_join
type ClusterMemberConfigKey struct {
	// The kind of configuration key (network, storage-pool, ...)
	// Example: storage-pool
	Entity string `json:"entity" yaml:"entity"`

	// The name of the object requiring this key
	// Example: local
	Name string `json:"name" yaml:"name"`

	// The name of the key
	// Example: source
	Key string `json:"key" yaml:"key"`

	// The value on the answering cluster member
	// Example: /dev/sdb
	Value string `json:"value" yaml:"value"`

	// A human friendly description key
	// Example: "source" property for storage pool "local"
	Description string `json:"description" yaml:"description"`
}

// ClusterPut represents the fields required to bootstrap or join a LXD
// cluster.
//
// swagger:model
//
// API extension: clustering
type ClusterPut struct {
	Cluster `yaml:",inline"`

	// The address of the cluster you wish to join
	// Example: 10.0.0.1:8443
	ClusterAddress string `json:"cluster_address" yaml:"cluster_address"`

	// The expected certificate (X509 PEM encoded) for the cluster
	// Example: X509 PEM certificate
	ClusterCertificate string `json:"cluster_certificate" yaml:"cluster_certificate"`

	// The local address to use for cluster communication
	// Example: 10.0.0.2:8443
	//
	// API extension: clustering_join
	ServerAddress string `json:"server_address" yaml:"server_address"`

	// The trust password of the cluster you're trying to join
	// Example: blah
	//
	// API extension: clustering_join
	ClusterPassword string `json:"cluster_password" yaml:"cluster_password"`
}

// ClusterMembersPost represents the fields required to request a join token to add a member to the cluster.
//
// swagger:model
//
// API extension: clustering_join_token
type ClusterMembersPost struct {
	// The name of the new cluster member
	// Example: lxd02
	ServerName string `json:"server_name" yaml:"server_name"`
}

// ClusterMemberJoinToken represents the fields contained within an encoded cluster member join token.
//
// swagger:model
//
// API extension: clustering_join_token
type ClusterMemberJoinToken struct {
	// The name of the new cluster member
	// Example: lxd02
	ServerName string `json:"server_name" yaml:"server_name"`

	// The fingerprint of the network certificate
	// Example: 57bb0ff4340b5bb28517e062023101adf788c37846dc8b619eb2c3cb4ef29436
	Fingerprint string `json:"fingerprint" yaml:"fingerprint"`

	// The addresses of existing online cluster members
	// Example: ["10.98.30.229:8443"]
	Addresses []string `json:"addresses" yaml:"addresses"`

	// The random join secret.
	// Example: 2b2284d44db32675923fe0d2020477e0e9be11801ff70c435e032b97028c35cd
	Secret string `json:"secret" yaml:"secret"`
}

// String encodes the cluster member join token as JSON and then Base64.
func (t *ClusterMemberJoinToken) String() string {
	joinTokenJSON, err := json.Marshal(t)
	if err != nil {
		return ""
	}

	return base64.StdEncoding.EncodeToString(joinTokenJSON)
}

// ClusterMemberPost represents the fields required to rename a LXD node.
//
// swagger:model
//
// API extension: clustering
type ClusterMemberPost struct {
	// The new name of the cluster member
	// Example: lxd02
	ServerName string `json:"server_name" yaml:"server_name"`
}

// ClusterMember represents the a LXD node in the cluster.
//
// swagger:model
//
// API extension: clustering
type ClusterMember struct {
	ClusterMemberPut `yaml:",inline"`

	// Name of the cluster member
	// Example: lxd01
	ServerName string `json:"server_name" yaml:"server_name"`

	// URL at which the cluster member can be reached
	// Example: https://10.0.0.1:8443
	URL string `json:"url" yaml:"url"`

	// Whether the cluster member is a database server
	// Example: true
	Database bool `json:"database" yaml:"database"`

	// Current status
	// Example: Online
	Status string `json:"status" yaml:"status"`

	// Additional status information
	// Example: fully operational
	Message string `json:"message" yaml:"message"`

	// The primary architecture of the cluster member
	// Example: x86_64
	//
	// API extension: clustering_architecture
	Architecture string `json:"architecture" yaml:"architecture"`
}

// Writable converts a full Profile struct into a ProfilePut struct (filters read-only fields)
func (member *ClusterMember) Writable() ClusterMemberPut {
	return member.ClusterMemberPut
}

// ClusterMemberPut represents the the modifiable fields of a LXD cluster member
//
// swagger:model
//
// API extension: clustering_edit_roles
type ClusterMemberPut struct {
	// List of roles held by this cluster member
	// Example: ["database"]
	//
	// API extension: clustering_roles
	Roles []string `json:"roles" yaml:"roles"`

	// Name of the failure domain for this cluster member
	// Example: rack1
	//
	// API extension: clustering_failure_domains
	FailureDomain string `json:"failure_domain" yaml:"failure_domain"`

	// Cluster member description
	// Example: AMD Epyc 32c/64t
	//
	// API extension: clustering_description
	Description string `json:"description" yaml:"description"`

	// Additional configuration information
	// Example: {"scheduler.instance": "all"}
	//
	// API extension: clustering_config
	Config map[string]string `json:"config" yaml:"config"`

	// List of cluster groups this member belongs to
	// Example: ["group1", "group2"]
	//
	// API extension: clustering_groups
	Groups []string `json:"groups" yaml:"groups"`
}

// ClusterCertificatePut represents the certificate and key pair for all members in a LXD Cluster
//
// swagger:model
//
// API extension: clustering_update_certs
type ClusterCertificatePut struct {
	// The new certificate (X509 PEM encoded) for the cluster
	// Example: X509 PEM certificate
	ClusterCertificate string `json:"cluster_certificate" yaml:"cluster_certificate"`

	// The new certificate key (X509 PEM encoded) for the cluster
	// Example: X509 PEM certificate key
	ClusterCertificateKey string `json:"cluster_certificate_key" yaml:"cluster_certificate_key"`
}

// ClusterMemberStatePost represents the fields required to evacuate a cluster member.
//
// swagger:model
//
// API extension: clustering_evacuation
type ClusterMemberStatePost struct {
	// The action to be performed. Valid actions are "evacuate" and "restore".
	// Example: evacuate
	Action string `json:"action" yaml:"action"`
}

// ClusterGroupsPost represents the fields available for a new cluster group.
//
// swagger:model
//
// API extension: clustering_groups
type ClusterGroupsPost struct {
	ClusterGroupPut

	// The new name of the cluster group
	// Example: group1
	Name string `json:"name" yaml:"name"`
}

// ClusterGroup represents a cluster group.
//
// swagger:model
//
// API extension: clustering_groups
type ClusterGroup struct {
	ClusterGroupPut  `yaml:",inline"`
	ClusterGroupPost `yaml:",inline"`
}

// ClusterGroupPost represents the fields required to rename a cluster group.
//
// swagger:model
//
// API extension: clustering_groups
type ClusterGroupPost struct {
	// The new name of the cluster group
	// Example: group1
	Name string `json:"name" yaml:"name"`
}

// ClusterGroupPut represents the modifiable fields of a cluster group.
//
// swagger:model
//
// API extension: clustering_groups
type ClusterGroupPut struct {
	// The description of the cluster group
	// Example: amd64 servers
	Description string `json:"description" yaml:"description"`

	// List of members in this group
	// Example: ["node1", "node3"]
	Members []string `json:"members" yaml:"members"`
}

// Writable converts a full ClusterGroup struct into a ClusterGroupPut struct (filters read-only fields)
func (c *ClusterGroup) Writable() ClusterGroupPut {
	return c.ClusterGroupPut
}
<commit_msg>shared/api/cluster: s/Base64/base64/<commit_after>package api

import (
	"encoding/base64"
	"encoding/json"
)

// Cluster represents high-level information about a LXD cluster.
//
// swagger:model
//
// API extension: clustering
type Cluster struct {
	// Name of the cluster member answering the request
	// Example: lxd01
	ServerName string `json:"server_name" yaml:"server_name"`

	// Whether clustering is enabled
	// Example: true
	Enabled bool `json:"enabled" yaml:"enabled"`

	// List of member configuration keys (used during join)
	// Example: []
	//
	// API extension: clustering_join
	MemberConfig []ClusterMemberConfigKey `json:"member_config" yaml:"member_config"`
}

// ClusterMemberConfigKey represents a single config key that a new member of
// the cluster is required to provide when joining.
//
// The Value field is empty when getting clustering information with GET
// /1.0/cluster, and should be filled by the joining node when performing a PUT
// /1.0/cluster join request.
//
// swagger:model
//
// API extension: clustering_join
type ClusterMemberConfigKey struct {
	// The kind of configuration key (network, storage-pool, ...)
	// Example: storage-pool
	Entity string `json:"entity" yaml:"entity"`

	// The name of the object requiring this key
	// Example: local
	Name string `json:"name" yaml:"name"`

	// The name of the key
	// Example: source
	Key string `json:"key" yaml:"key"`

	// The value on the answering cluster member
	// Example: /dev/sdb
	Value string `json:"value" yaml:"value"`

	// A human friendly description key
	// Example: "source" property for storage pool "local"
	Description string `json:"description" yaml:"description"`
}

// ClusterPut represents the fields required to bootstrap or join a LXD
// cluster.
//
// swagger:model
//
// API extension: clustering
type ClusterPut struct {
	Cluster `yaml:",inline"`

	// The address of the cluster you wish to join
	// Example: 10.0.0.1:8443
	ClusterAddress string `json:"cluster_address" yaml:"cluster_address"`

	// The expected certificate (X509 PEM encoded) for the cluster
	// Example: X509 PEM certificate
	ClusterCertificate string `json:"cluster_certificate" yaml:"cluster_certificate"`

	// The local address to use for cluster communication
	// Example: 10.0.0.2:8443
	//
	// API extension: clustering_join
	ServerAddress string `json:"server_address" yaml:"server_address"`

	// The trust password of the cluster you're trying to join
	// Example: blah
	//
	// API extension: clustering_join
	ClusterPassword string `json:"cluster_password" yaml:"cluster_password"`
}

// ClusterMembersPost represents the fields required to request a join token to add a member to the cluster.
//
// swagger:model
//
// API extension: clustering_join_token
type ClusterMembersPost struct {
	// The name of the new cluster member
	// Example: lxd02
	ServerName string `json:"server_name" yaml:"server_name"`
}

// ClusterMemberJoinToken represents the fields contained within an encoded cluster member join token.
//
// swagger:model
//
// API extension: clustering_join_token
type ClusterMemberJoinToken struct {
	// The name of the new cluster member
	// Example: lxd02
	ServerName string `json:"server_name" yaml:"server_name"`

	// The fingerprint of the network certificate
	// Example: 57bb0ff4340b5bb28517e062023101adf788c37846dc8b619eb2c3cb4ef29436
	Fingerprint string `json:"fingerprint" yaml:"fingerprint"`

	// The addresses of existing online cluster members
	// Example: ["10.98.30.229:8443"]
	Addresses []string `json:"addresses" yaml:"addresses"`

	// The random join secret.
	// Example: 2b2284d44db32675923fe0d2020477e0e9be11801ff70c435e032b97028c35cd
	Secret string `json:"secret" yaml:"secret"`
}

// String encodes the cluster member join token as JSON and then base64.
func (t *ClusterMemberJoinToken) String() string {
	joinTokenJSON, err := json.Marshal(t)
	if err != nil {
		return ""
	}

	return base64.StdEncoding.EncodeToString(joinTokenJSON)
}

// ClusterMemberPost represents the fields required to rename a LXD node.
//
// swagger:model
//
// API extension: clustering
type ClusterMemberPost struct {
	// The new name of the cluster member
	// Example: lxd02
	ServerName string `json:"server_name" yaml:"server_name"`
}

// ClusterMember represents the a LXD node in the cluster.
//
// swagger:model
//
// API extension: clustering
type ClusterMember struct {
	ClusterMemberPut `yaml:",inline"`

	// Name of the cluster member
	// Example: lxd01
	ServerName string `json:"server_name" yaml:"server_name"`

	// URL at which the cluster member can be reached
	// Example: https://10.0.0.1:8443
	URL string `json:"url" yaml:"url"`

	// Whether the cluster member is a database server
	// Example: true
	Database bool `json:"database" yaml:"database"`

	// Current status
	// Example: Online
	Status string `json:"status" yaml:"status"`

	// Additional status information
	// Example: fully operational
	Message string `json:"message" yaml:"message"`

	// The primary architecture of the cluster member
	// Example: x86_64
	//
	// API extension: clustering_architecture
	Architecture string `json:"architecture" yaml:"architecture"`
}

// Writable converts a full Profile struct into a ProfilePut struct (filters read-only fields)
func (member *ClusterMember) Writable() ClusterMemberPut {
	return member.ClusterMemberPut
}

// ClusterMemberPut represents the the modifiable fields of a LXD cluster member
//
// swagger:model
//
// API extension: clustering_edit_roles
type ClusterMemberPut struct {
	// List of roles held by this cluster member
	// Example: ["database"]
	//
	// API extension: clustering_roles
	Roles []string `json:"roles" yaml:"roles"`

	// Name of the failure domain for this cluster member
	// Example: rack1
	//
	// API extension: clustering_failure_domains
	FailureDomain string `json:"failure_domain" yaml:"failure_domain"`

	// Cluster member description
	// Example: AMD Epyc 32c/64t
	//
	// API extension: clustering_description
	Description string `json:"description" yaml:"description"`

	// Additional configuration information
	// Example: {"scheduler.instance": "all"}
	//
	// API extension: clustering_config
	Config map[string]string `json:"config" yaml:"config"`

	// List of cluster groups this member belongs to
	// Example: ["group1", "group2"]
	//
	// API extension: clustering_groups
	Groups []string `json:"groups" yaml:"groups"`
}

// ClusterCertificatePut represents the certificate and key pair for all members in a LXD Cluster
//
// swagger:model
//
// API extension: clustering_update_certs
type ClusterCertificatePut struct {
	// The new certificate (X509 PEM encoded) for the cluster
	// Example: X509 PEM certificate
	ClusterCertificate string `json:"cluster_certificate" yaml:"cluster_certificate"`

	// The new certificate key (X509 PEM encoded) for the cluster
	// Example: X509 PEM certificate key
	ClusterCertificateKey string `json:"cluster_certificate_key" yaml:"cluster_certificate_key"`
}

// ClusterMemberStatePost represents the fields required to evacuate a cluster member.
//
// swagger:model
//
// API extension: clustering_evacuation
type ClusterMemberStatePost struct {
	// The action to be performed. Valid actions are "evacuate" and "restore".
	// Example: evacuate
	Action string `json:"action" yaml:"action"`
}

// ClusterGroupsPost represents the fields available for a new cluster group.
//
// swagger:model
//
// API extension: clustering_groups
type ClusterGroupsPost struct {
	ClusterGroupPut

	// The new name of the cluster group
	// Example: group1
	Name string `json:"name" yaml:"name"`
}

// ClusterGroup represents a cluster group.
//
// swagger:model
//
// API extension: clustering_groups
type ClusterGroup struct {
	ClusterGroupPut  `yaml:",inline"`
	ClusterGroupPost `yaml:",inline"`
}

// ClusterGroupPost represents the fields required to rename a cluster group.
//
// swagger:model
//
// API extension: clustering_groups
type ClusterGroupPost struct {
	// The new name of the cluster group
	// Example: group1
	Name string `json:"name" yaml:"name"`
}

// ClusterGroupPut represents the modifiable fields of a cluster group.
//
// swagger:model
//
// API extension: clustering_groups
type ClusterGroupPut struct {
	// The description of the cluster group
	// Example: amd64 servers
	Description string `json:"description" yaml:"description"`

	// List of members in this group
	// Example: ["node1", "node3"]
	Members []string `json:"members" yaml:"members"`
}

// Writable converts a full ClusterGroup struct into a ClusterGroupPut struct (filters read-only fields)
func (c *ClusterGroup) Writable() ClusterGroupPut {
	return c.ClusterGroupPut
}
<|endoftext|>