<commit_before>package server

import (
	"container/list"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"runtime/debug"
	"sync"
	"time"

	"warcluster/entities"
	"warcluster/server/response"
)

// Thread-safe pool of all clients, with opened sockets.
type ClientPool struct {
	mutex  sync.Mutex
	pool   map[string]*list.List
	ticker *time.Ticker
}

func NewClientPool(ticker time.Duration) *ClientPool {
	cp := new(ClientPool)
	cp.pool = make(map[string]*list.List)
	cp.ticker = time.NewTicker(ticker * time.Millisecond)
	go cp.runStateChangeCycle()
	return cp
}

func (cp *ClientPool) runStateChangeCycle() {
	defer func() {
		if panicked := recover(); panicked != nil {
			log.Println(fmt.Sprintf(
				"%s\n\nState change cycle has panicked!:\n\n%s",
				panicked,
				debug.Stack(),
			))
			go cp.runStateChangeCycle()
		}
	}()
	for _ = range cp.ticker.C {
		for _, clients := range cp.pool {
			for element := clients.Front(); element != nil; element = element.Next() {
				element.Value.(*Client).sendStateChange()
			}
		}
	}
}

// Returns player's instance by username in order not to hit the database
func (cp *ClientPool) Player(username string) (*entities.Player, error) {
	if element, ok := cp.pool[username]; ok {
		return element.Front().Value.(*Client).Player, nil
	}
	return nil, errors.New("Player not logged in")
}

// Adds the given client to the pool.
func (cp *ClientPool) Add(client *Client) {
	cp.mutex.Lock()
	defer cp.mutex.Unlock()

	if _, ok := cp.pool[client.Player.Username]; !ok {
		cp.pool[client.Player.Username] = list.New()
	}
	element := cp.pool[client.Player.Username].PushBack(client)
	client.poolElement = element
}

// Remove the client to the pool.
// It is safe to remove non-existing client.
func (cp *ClientPool) Remove(client *Client) {
	cp.mutex.Lock()
	defer cp.mutex.Unlock()

	playerInPool, ok := cp.pool[client.Player.Username]
	if ok {
		playerInPool.Remove(client.poolElement)

		if playerInPool.Len() == 0 {
			delete(cp.pool, client.Player.Username)
		}
	}
}

// Broadcast sends the given message to every session in the pool.
func (cp *ClientPool) BroadcastToAll(response response.Responser) {
	for _, clients := range cp.pool {

		client := clients.Front().Value.(*Client)
		response.Sanitize(client.Player)
		cp.Send(client.Player, response)
	}
}

// Broadcasts state change of an entity to all interested parties
func (cp *ClientPool) Broadcast(entity entities.Entity) {
	defer func() {
		if panicked := recover(); panicked != nil {
			return
		}
	}()

	for _, clients := range cp.pool {
		for element := clients.Front(); element != nil; element = element.Next() {
			element.Value.(*Client).pushStateChange(entity)
		}
	}
}

func (cp *ClientPool) UpdateSpyReports(player *entities.Player) {
	defer func() {
		if panicked := recover(); panicked != nil {
			return
		}
	}()

	poolMember := cp.pool[player.Username]
	for element := poolMember.Front(); element != nil; element = element.Next() {
		client := element.Value.(*Client)
		client.Player.UpdateSpyReports()
	}
}

// Sanitizes given response and sends it to every player's session in the pool.
func (cp *ClientPool) Send(player *entities.Player, response response.Responser) {
	defer func() {
		if panicked := recover(); panicked != nil {
			return
		}
	}()
	response.Sanitize(player)

	message, _ := json.Marshal(response)

	for element := cp.pool[player.Username].Front(); element != nil; element = element.Next() {
		client := element.Value.(*Client)
		client.Session.Send(message)
	}
}
<commit_msg>Deprecate ClientPool.BroadcastToAll<commit_after>package server

import (
	"container/list"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"runtime/debug"
	"sync"
	"time"

	"warcluster/entities"
	"warcluster/server/response"
)

// Thread-safe pool of all clients, with opened sockets.
type ClientPool struct {
	mutex  sync.Mutex
	pool   map[string]*list.List
	ticker *time.Ticker
}

func NewClientPool(ticker time.Duration) *ClientPool {
	cp := new(ClientPool)
	cp.pool = make(map[string]*list.List)
	cp.ticker = time.NewTicker(ticker * time.Millisecond)
	go cp.runStateChangeCycle()
	return cp
}

func (cp *ClientPool) runStateChangeCycle() {
	defer func() {
		if panicked := recover(); panicked != nil {
			log.Println(fmt.Sprintf(
				"%s\n\nState change cycle has panicked!:\n\n%s",
				panicked,
				debug.Stack(),
			))
			go cp.runStateChangeCycle()
		}
	}()
	for _ = range cp.ticker.C {
		for _, clients := range cp.pool {
			for element := clients.Front(); element != nil; element = element.Next() {
				element.Value.(*Client).sendStateChange()
			}
		}
	}
}

// Returns player's instance by username in order not to hit the database
func (cp *ClientPool) Player(username string) (*entities.Player, error) {
	if element, ok := cp.pool[username]; ok {
		return element.Front().Value.(*Client).Player, nil
	}
	return nil, errors.New("Player not logged in")
}

// Adds the given client to the pool.
func (cp *ClientPool) Add(client *Client) {
	cp.mutex.Lock()
	defer cp.mutex.Unlock()

	if _, ok := cp.pool[client.Player.Username]; !ok {
		cp.pool[client.Player.Username] = list.New()
	}
	element := cp.pool[client.Player.Username].PushBack(client)
	client.poolElement = element
}

// Remove the client to the pool.
// It is safe to remove non-existing client.
func (cp *ClientPool) Remove(client *Client) {
	cp.mutex.Lock()
	defer cp.mutex.Unlock()

	playerInPool, ok := cp.pool[client.Player.Username]
	if ok {
		playerInPool.Remove(client.poolElement)

		if playerInPool.Len() == 0 {
			delete(cp.pool, client.Player.Username)
		}
	}
}

// Broadcast sends the given message to every session in the pool.
// WARNING: This method is DEPRECATED! Use cp.Broadcast() instead.
func (cp *ClientPool) BroadcastToAll(response response.Responser) {
	for _, clients := range cp.pool {

		client := clients.Front().Value.(*Client)
		response.Sanitize(client.Player)
		cp.Send(client.Player, response)
	}
}

// Broadcasts state change of an entity to all interested parties
func (cp *ClientPool) Broadcast(entity entities.Entity) {
	defer func() {
		if panicked := recover(); panicked != nil {
			return
		}
	}()

	for _, clients := range cp.pool {
		for element := clients.Front(); element != nil; element = element.Next() {
			element.Value.(*Client).pushStateChange(entity)
		}
	}
}

func (cp *ClientPool) UpdateSpyReports(player *entities.Player) {
	defer func() {
		if panicked := recover(); panicked != nil {
			return
		}
	}()

	poolMember := cp.pool[player.Username]
	for element := poolMember.Front(); element != nil; element = element.Next() {
		client := element.Value.(*Client)
		client.Player.UpdateSpyReports()
	}
}

// Sanitizes given response and sends it to every player's session in the pool.
func (cp *ClientPool) Send(player *entities.Player, response response.Responser) {
	defer func() {
		if panicked := recover(); panicked != nil {
			return
		}
	}()
	response.Sanitize(player)

	message, _ := json.Marshal(response)

	for element := cp.pool[player.Username].Front(); element != nil; element = element.Next() {
		client := element.Value.(*Client)
		client.Session.Send(message)
	}
}
<|endoftext|>


<commit_before>package chrome

import (
	"context"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net"
	"sync"

	"github.com/gorilla/websocket"
	"github.com/unixpickle/essentials"
)

// Conn is a connection to a protocol endpoint.
type Conn struct {
	ws *websocket.Conn

	sendLock sync.Mutex
	curID    int

	// Closed when the read loop is complete.
	doneChan <-chan struct{}

	// Keep track of calls that are awaiting responses.
	waitingLock sync.Mutex
	waiting     map[int]*waitingCall

	// Callers which are polling for events.
	pollingLock sync.Mutex
	polling     map[string][]*waitingCall

	firstErrLock sync.RWMutex
	firstErr     error

	logLock sync.RWMutex
	log     []string
}

// NewConn connects to an endpoint's WebSocket URL.
func NewConn(ctx context.Context, websocketURL string) (conn *Conn, err error) {
	defer essentials.AddCtxTo("connect to DevTools endpoint", &err)
	if websocketURL == "" {
		return nil, errors.New("empty websocket URL")
	}
	dialer := websocket.Dialer{
		NetDial: func(network, addr string) (net.Conn, error) {
			return (&net.Dialer{}).DialContext(ctx, network, addr)
		},
	}
	ws, _, err := dialer.Dial(websocketURL, nil)
	if err != nil {
		return
	}
	doneChan := make(chan struct{})
	conn = &Conn{
		ws:       ws,
		doneChan: doneChan,
		waiting:  map[int]*waitingCall{},
		polling:  map[string][]*waitingCall{},
	}
	go func() {
		defer close(doneChan)
		conn.readLoop()
	}()
	if err := conn.call(ctx, "Log.enable", nil, nil); err != nil {
		conn.Close()
		return nil, err
	}
	return
}

// Close closes the connection.
func (c *Conn) Close() error {
	err := c.ws.Close()
	<-c.doneChan
	return err
}

// Error returns the first connection error encountered.
// If no errors have been encountered, nil is returned.
func (c *Conn) Error() error {
	c.firstErrLock.RLock()
	defer c.firstErrLock.RUnlock()
	return c.firstErr
}

// ConsoleLog returns a copy of the console log messages.
// This may be cleared on page refresh.
func (c *Conn) ConsoleLog() []string {
	c.logLock.RLock()
	defer c.logLock.RUnlock()
	return append([]string{}, c.log...)
}

// clearLog clears the log returned by consoleLog.
func (c *Conn) clearLog() {
	c.logLock.Lock()
	defer c.logLock.Unlock()
	c.log = nil
}

// call makes an API call.
//
// The return value of the API call is unmarshalled into
// resObj following the rules of encoding/json.
//
// If a connection or JSON error occurs, it is returned.
// Just because a call fails with an error doesn't mean
// the connection is dead; it could simply mean that the
// result didn't unmarshal.
func (c *Conn) call(ctx context.Context, name string, params interface{},
	resObj interface{}) (err error) {
	defer essentials.AddCtxTo("DevTools "+name+" call", &err)

	payload := map[string]interface{}{"method": name}
	if params != nil {
		payload["params"] = params
	}
	doneChan := make(chan error, 1)

	c.sendLock.Lock()
	c.curID++
	payload["id"] = c.curID

	c.waitingLock.Lock()
	c.waiting[c.curID] = &waitingCall{
		OutPtr:   resObj,
		DoneChan: doneChan,
	}
	c.waitingLock.Unlock()

	err = c.ws.WriteJSON(payload)
	c.sendLock.Unlock()

	if err != nil {
		c.gotError("write DevTools message", err)
		return
	}

	select {
	case unmarshalErr := <-doneChan:
		return unmarshalErr
	case <-c.doneChan:
		return errors.New("closed before reading return value")
	case <-ctx.Done():
		return ctx.Err()
	}
}

// poll asynchronously waits for an event.
//
// This works very similarly to call, except that poll is
// non-blocking and the error is sent over a channel.
//
// The event handler is guaranteed to be registered by the
// time poll returns.
// The returned channel is closed after the event arrives.
// If no error occurs, the channel will be closed without
// having any value sent to it.
//
// The resObj argument may be written after poll returns,
// since poll is non-blocking.
// However, it will never be written after the error
// channel has been closed.
func (c *Conn) poll(ctx context.Context, name string,
	resObj interface{}) <-chan error {
	doneChan := make(chan error, 1)

	c.pollingLock.Lock()
	c.polling[name] = append(c.polling[name], &waitingCall{
		OutPtr:   resObj,
		DoneChan: doneChan,
	})
	c.pollingLock.Unlock()

	res := make(chan error, 1)
	go func() {
		var err error
		select {
		case err = <-doneChan:
		case <-c.doneChan:
			err = errors.New("closed before receiving event")
		case <-ctx.Done():
			err = ctx.Err()
		}
		if err != nil {
			res <- essentials.AddCtx("poll DevTools "+name+" event", err)
		}
		close(res)
	}()

	return res
}

func (c *Conn) readLoop() {
	for {
		const errContext = "read DevTools message"

		_, reader, err := c.ws.NextReader()
		if err != nil {
			if err == io.EOF {
				err = io.ErrUnexpectedEOF
			}
			c.gotError(errContext, err)
			return
		}
		data, err := ioutil.ReadAll(reader)
		if err != nil {
			c.gotError(errContext, err)
			return
		}

		var obj struct {
			ID     int    `json:"id"`
			Method string `json:"method"`
		}
		if err := json.Unmarshal(data, &obj); err != nil {
			c.gotError(errContext, err)
			return
		}

		if obj.ID != 0 {
			// We don't run this asynchronously because of a race
			// condition where the remote disconnects after sending
			// the return value.
			c.handleReturnValue(obj.ID, data)
		} else {
			c.handleEvent(obj.Method, data)
		}
	}
}

func (c *Conn) handleReturnValue(id int, data []byte) {
	c.waitingLock.Lock()
	waiter := c.waiting[id]
	delete(c.waiting, id)
	c.waitingLock.Unlock()

	if waiter == nil {
		// Server replied to a message we didn't send.
		return
	}

	var obj struct {
		Result interface{} `json:"result"`
	}
	obj.Result = waiter.OutPtr
	waiter.DoneChan <- json.Unmarshal(data, &obj)
}

func (c *Conn) handleEvent(method string, data []byte) {
	if method == "Log.entryAdded" {
		var entryObj struct {
			Params struct {
				Entry struct {
					Text string `json:"text"`
				} `json:"entry"`
			} `json:"params"`
		}
		log.Println(string(data))
		if json.Unmarshal(data, &entryObj) == nil {
			c.logLock.Lock()
			c.log = append(c.log, entryObj.Params.Entry.Text)
			c.logLock.Unlock()
		}
	}

	c.pollingLock.Lock()
	pollers := c.polling[method]
	delete(c.polling, method)
	c.pollingLock.Unlock()

	for _, poller := range pollers {
		var obj struct {
			Params interface{} `json:"params"`
		}
		obj.Params = poller.OutPtr
		poller.DoneChan <- json.Unmarshal(data, &obj)
	}
}

func (c *Conn) gotError(ctx string, e error) {
	c.firstErrLock.Lock()
	defer c.firstErrLock.Unlock()
	if c.firstErr == nil {
		c.firstErr = essentials.AddCtx(ctx, e)
	}
}

type waitingCall struct {
	OutPtr   interface{}
	DoneChan chan<- error
}
<commit_msg>remove log<commit_after>package chrome

import (
	"context"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net"
	"sync"

	"github.com/gorilla/websocket"
	"github.com/unixpickle/essentials"
)

// Conn is a connection to a protocol endpoint.
type Conn struct {
	ws *websocket.Conn

	sendLock sync.Mutex
	curID    int

	// Closed when the read loop is complete.
	doneChan <-chan struct{}

	// Keep track of calls that are awaiting responses.
	waitingLock sync.Mutex
	waiting     map[int]*waitingCall

	// Callers which are polling for events.
	pollingLock sync.Mutex
	polling     map[string][]*waitingCall

	firstErrLock sync.RWMutex
	firstErr     error

	logLock sync.RWMutex
	log     []string
}

// NewConn connects to an endpoint's WebSocket URL.
func NewConn(ctx context.Context, websocketURL string) (conn *Conn, err error) {
	defer essentials.AddCtxTo("connect to DevTools endpoint", &err)
	if websocketURL == "" {
		return nil, errors.New("empty websocket URL")
	}
	dialer := websocket.Dialer{
		NetDial: func(network, addr string) (net.Conn, error) {
			return (&net.Dialer{}).DialContext(ctx, network, addr)
		},
	}
	ws, _, err := dialer.Dial(websocketURL, nil)
	if err != nil {
		return
	}
	doneChan := make(chan struct{})
	conn = &Conn{
		ws:       ws,
		doneChan: doneChan,
		waiting:  map[int]*waitingCall{},
		polling:  map[string][]*waitingCall{},
	}
	go func() {
		defer close(doneChan)
		conn.readLoop()
	}()
	if err := conn.call(ctx, "Log.enable", nil, nil); err != nil {
		conn.Close()
		return nil, err
	}
	return
}

// Close closes the connection.
func (c *Conn) Close() error {
	err := c.ws.Close()
	<-c.doneChan
	return err
}

// Error returns the first connection error encountered.
// If no errors have been encountered, nil is returned.
func (c *Conn) Error() error {
	c.firstErrLock.RLock()
	defer c.firstErrLock.RUnlock()
	return c.firstErr
}

// ConsoleLog returns a copy of the console log messages.
// This may be cleared on page refresh.
func (c *Conn) ConsoleLog() []string {
	c.logLock.RLock()
	defer c.logLock.RUnlock()
	return append([]string{}, c.log...)
}

// clearLog clears the log returned by consoleLog.
func (c *Conn) clearLog() {
	c.logLock.Lock()
	defer c.logLock.Unlock()
	c.log = nil
}

// call makes an API call.
//
// The return value of the API call is unmarshalled into
// resObj following the rules of encoding/json.
//
// If a connection or JSON error occurs, it is returned.
// Just because a call fails with an error doesn't mean
// the connection is dead; it could simply mean that the
// result didn't unmarshal.
func (c *Conn) call(ctx context.Context, name string, params interface{},
	resObj interface{}) (err error) {
	defer essentials.AddCtxTo("DevTools "+name+" call", &err)

	payload := map[string]interface{}{"method": name}
	if params != nil {
		payload["params"] = params
	}
	doneChan := make(chan error, 1)

	c.sendLock.Lock()
	c.curID++
	payload["id"] = c.curID

	c.waitingLock.Lock()
	c.waiting[c.curID] = &waitingCall{
		OutPtr:   resObj,
		DoneChan: doneChan,
	}
	c.waitingLock.Unlock()

	err = c.ws.WriteJSON(payload)
	c.sendLock.Unlock()

	if err != nil {
		c.gotError("write DevTools message", err)
		return
	}

	select {
	case unmarshalErr := <-doneChan:
		return unmarshalErr
	case <-c.doneChan:
		return errors.New("closed before reading return value")
	case <-ctx.Done():
		return ctx.Err()
	}
}

// poll asynchronously waits for an event.
//
// This works very similarly to call, except that poll is
// non-blocking and the error is sent over a channel.
//
// The event handler is guaranteed to be registered by the
// time poll returns.
// The returned channel is closed after the event arrives.
// If no error occurs, the channel will be closed without
// having any value sent to it.
//
// The resObj argument may be written after poll returns,
// since poll is non-blocking.
// However, it will never be written after the error
// channel has been closed.
func (c *Conn) poll(ctx context.Context, name string,
	resObj interface{}) <-chan error {
	doneChan := make(chan error, 1)

	c.pollingLock.Lock()
	c.polling[name] = append(c.polling[name], &waitingCall{
		OutPtr:   resObj,
		DoneChan: doneChan,
	})
	c.pollingLock.Unlock()

	res := make(chan error, 1)
	go func() {
		var err error
		select {
		case err = <-doneChan:
		case <-c.doneChan:
			err = errors.New("closed before receiving event")
		case <-ctx.Done():
			err = ctx.Err()
		}
		if err != nil {
			res <- essentials.AddCtx("poll DevTools "+name+" event", err)
		}
		close(res)
	}()

	return res
}

func (c *Conn) readLoop() {
	for {
		const errContext = "read DevTools message"

		_, reader, err := c.ws.NextReader()
		if err != nil {
			if err == io.EOF {
				err = io.ErrUnexpectedEOF
			}
			c.gotError(errContext, err)
			return
		}
		data, err := ioutil.ReadAll(reader)
		if err != nil {
			c.gotError(errContext, err)
			return
		}

		var obj struct {
			ID     int    `json:"id"`
			Method string `json:"method"`
		}
		if err := json.Unmarshal(data, &obj); err != nil {
			c.gotError(errContext, err)
			return
		}

		if obj.ID != 0 {
			// We don't run this asynchronously because of a race
			// condition where the remote disconnects after sending
			// the return value.
			c.handleReturnValue(obj.ID, data)
		} else {
			c.handleEvent(obj.Method, data)
		}
	}
}

func (c *Conn) handleReturnValue(id int, data []byte) {
	c.waitingLock.Lock()
	waiter := c.waiting[id]
	delete(c.waiting, id)
	c.waitingLock.Unlock()

	if waiter == nil {
		// Server replied to a message we didn't send.
		return
	}

	var obj struct {
		Result interface{} `json:"result"`
	}
	obj.Result = waiter.OutPtr
	waiter.DoneChan <- json.Unmarshal(data, &obj)
}

func (c *Conn) handleEvent(method string, data []byte) {
	if method == "Log.entryAdded" {
		var entryObj struct {
			Params struct {
				Entry struct {
					Text string `json:"text"`
				} `json:"entry"`
			} `json:"params"`
		}
		if json.Unmarshal(data, &entryObj) == nil {
			c.logLock.Lock()
			c.log = append(c.log, entryObj.Params.Entry.Text)
			c.logLock.Unlock()
		}
	}

	c.pollingLock.Lock()
	pollers := c.polling[method]
	delete(c.polling, method)
	c.pollingLock.Unlock()

	for _, poller := range pollers {
		var obj struct {
			Params interface{} `json:"params"`
		}
		obj.Params = poller.OutPtr
		poller.DoneChan <- json.Unmarshal(data, &obj)
	}
}

func (c *Conn) gotError(ctx string, e error) {
	c.firstErrLock.Lock()
	defer c.firstErrLock.Unlock()
	if c.firstErr == nil {
		c.firstErr = essentials.AddCtx(ctx, e)
	}
}

type waitingCall struct {
	OutPtr   interface{}
	DoneChan chan<- error
}
<|endoftext|>


<commit_before>// Copyright 2016 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package gitea

import (
	"bytes"
	"encoding/json"
	"fmt"
)

// AddCollaboratorOption options when add some user as a collaborator of a repository
type AddCollaboratorOption struct {
	Permission *string `json:"permission"`
}

// AddCollaborator add some user as a collaborator of a repository
func (c *Client) AddCollaborator(user, repo, collaborator string, opt AddCollaboratorOption) error {
	body, err := json.Marshal(&opt)
	if err != nil {
		return err
	}
	_, err = c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, bytes.NewReader(body))
	return err
}
<commit_msg>Functions for Collaborators<commit_after>// Copyright 2016 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package gitea

import (
	"bytes"
	"encoding/json"
	"fmt"
)

// ListCollaborators list a repository's collaborators
func (c *Client) ListCollaborators(user, repo string) ([]*User, error) {
	collaborators := make([]*User, 0, 10)
	err := c.getParsedResponse("GET",
		fmt.Sprintf("/repos/%s/%s/collaborators", user, repo),
		nil, nil, &collaborators)
	return collaborators, err
}

// IsCollaborator check if a user is a collaborator of a repository
func (c *Client) IsCollaborator(user, repo, collaborator string) (bool, error) {
	status, err := c.getStatusCode("GET",
		fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator),
		nil, nil)
	if err != nil {
		return false, err
	}
	if status == 204 {
		return true, nil
	}
	return false, nil
}

// AddCollaboratorOption options when add some user as a collaborator of a repository
type AddCollaboratorOption struct {
	Permission *string `json:"permission"`
}

// AddCollaborator add some user as a collaborator of a repository
func (c *Client) AddCollaborator(user, repo, collaborator string, opt AddCollaboratorOption) error {
	body, err := json.Marshal(&opt)
	if err != nil {
		return err
	}
	_, err = c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, bytes.NewReader(body))
	return err
}

// DeleteCollaborator remove a collaborator from a repository
func (c *Client) DeleteCollaborator(user, repo, collaborator string) error {
	_, err := c.getResponse("DELETE",
		fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator),
		nil, nil)
	return err
}
<|endoftext|>


<commit_before>package sslprobe

import (
	"crypto/rand"
	"fmt"
	"net"
)

func CipherPreference(host string, port int, version TLSVersion) []CipherInfo {
	maxl := len(AllCiphers)
	rv := make([]CipherInfo, maxl)
	copy(rv, AllCiphers)
	candidates := 0

	for candidates < maxl {
		ciph, vv, _ := Connect(host, port, version, rv[candidates:])
		if ciph.ID != 0x0000 && vv == version {
			for i, c := range rv {
				if i <= candidates {
					continue
				}
				if c.ID == ciph.ID {
					for j := i; j > candidates; j-- {
						rv[j] = rv[j-1]
					}
					rv[candidates] = ciph
					break
				}
			}
			candidates++
		} else {
			break
		}
	}
	return rv[0:candidates]
}

type supportedProtocol struct {
	Version   TLSVersion
	Supported bool
}

func SupportedProtocols(host string, port int) []supportedProtocol {
	rv := make([]supportedProtocol, 0, 6)
	all := []TLSVersion{SSL_2_0, SSL_3_0, TLS_1_0, TLS_1_1, TLS_1_2, TLS_1_3}

	for _, v := range all {
		cph, vv, _ := Connect(host, port, v, AllCiphers)
		rv = append(rv, supportedProtocol{v, cph.ID != 0x0000 && v == vv})
	}
	return rv
}

func Connect(host string, port int, version TLSVersion, ciphers []CipherInfo) (rv CipherInfo, tls_version TLSVersion, err error) {
	serverHello, _, _, err := HalfHandshake(host, port, version, ciphers)
	if err != nil {
		return
	}
	sess_l := int(serverHello[34])
	rv = IDCipher(uint16(serverHello[35+sess_l])<<8 | uint16(serverHello[36+sess_l]))
	tls_version = TLSVersion(uint16(serverHello[0])<<8 | uint16(serverHello[1]))
	return
}

func HalfHandshake(host string, port int, version TLSVersion, ciphers []CipherInfo) (serverHello, serverCertificate, serverKeyExchange []byte, err error) {
	var c net.Conn
	c, err = net.Dial("tcp", fmt.Sprintf("%s:%d", host, port))
	if err != nil {
		return
	}

	// Be polite - send a fatal alert before hanging up
	defer func() {
		c.Write([]byte{21, byte(uint(version) >> 8), byte(uint(version)), 0, 2, 2, 0})
		c.Close()
	}()

	serverName := []byte(host)
	extension_length := 2 + 2 + 2 + 3 + len(serverName)
	clienthello_length := 46 + 2*len(ciphers) + 2 + 2 + extension_length

	clientHello := make([]byte, clienthello_length)
	clientHello[0] = 22 // handshake
	pint2(clientHello[1:], int(version))
	pint2(clientHello[3:], clienthello_length-5)
	clientHello[5] = 1 // client_hello
	pint3(clientHello[6:], clienthello_length-9)
	pint2(clientHello[9:], int(version))
	rand.Read(clientHello[11:42])
	for j := 0; j < 32; j++ {
		clientHello[11+j] = byte((j%8 + 1) * 17)
	}
	clientHello[43] = 0 // Session ID length

	// Cipher List
	pint2(clientHello[44:], 2*len(ciphers))
	for i, c := range ciphers {
		pint2(clientHello[46+2*i:], int(c.ID))
	}
	idx := 46 + 2*len(ciphers)
	clientHello[idx+0] = 1 // Compression methods length
	clientHello[idx+1] = 0 // None

	idx += 2
	// Extensions
	pint2(clientHello[idx:], extension_length)

	// Server Name
	pint2(clientHello[idx+2:], 0) // server_name
	pint2(clientHello[idx+4:], 2+3+len(serverName))
	idx += 6
	pint2(clientHello[idx:], 3+len(serverName))
	idx += 2
	clientHello[idx] = 0
	pint2(clientHello[idx+1:], len(serverName))
	copy(clientHello[idx+3:], serverName)

	// fmt.Printf("%s", clientHello)
	//return

	_, err = c.Write(clientHello)
	if err != nil {
		return
	}

	hstype, serverHello, err := NextHandshake(c)
	if err != nil {
		serverHello = nil
		if alert, ok := err.(Alert); ok {
			// Ignore 'unrecognized name' warnings.
			if alert.Level == 1 && alert.Description == 112 {
				fmt.Printf("  ignored: %s\n", alert)
				hstype, serverHello, err = NextHandshake(c)
				if err != nil {
					serverHello = nil
					return
				}
			} else {
				return
			}
		} else {
			return
		}
	}
	if hstype != 2 {
		serverHello = nil
		err = fmt.Errorf("Was expecting a ServerHello.")
		return
	}

	sess_l := int(serverHello[34])
	cipher := IDCipher(uint16(serverHello[35+sess_l])<<8 | uint16(serverHello[36+sess_l]))

	if cipher.Auth == AU_RSA || cipher.Auth == AU_DSA || cipher.Auth == AU_ECDSA {
		hstype, serverCertificate, err = NextHandshake(c)
		if err != nil {
			serverCertificate = nil
			return
		}
		if hstype != 11 {
			serverCertificate = nil
			err = fmt.Errorf("Was expecting a Certificate")
			return
		}
	}

	if cipher.Kex == KX_ECDHE || cipher.Kex == KX_FFDHE {
		hstype, serverKeyExchange, err = NextHandshake(c)
		if err != nil {
			serverKeyExchange = nil
			return
		}
		if hstype != 12 {
			serverKeyExchange = nil
			err = fmt.Errorf("Was expecting a ServerKeyExchange")
			return
		}
	}

	return
}

// Take a uint and stick it in the byte slice
func pint2(target []byte, source int) {
	target[0] = byte(source >> 8)
	target[1] = byte(source & 255)
}
func pint3(target []byte, source int) {
	target[0] = byte(source >> 16)
	target[1] = byte(source >> 8)
	target[2] = byte(source & 255)
}

var ERR_UnexpectedContentType error = fmt.Errorf("Unexpected ContentType")

func ReadCapsule(c net.Conn, expectedContentType byte) ([]byte, error) {
	lb := make([]byte, 5)
	_, err := c.Read(lb)
	if err != nil {
		return nil, err
	}

	length := (int(lb[3]) << 8) | int(lb[4])
	rv := make([]byte, length)
	_, err = c.Read(rv)
	if err != nil {
		return nil, err
	}

	if lb[0] == 21 {
		// This is a TLS alert, and therefore probably an error
		return nil, Alert{rv[0], rv[1]}
	} else if lb[0] != expectedContentType {
		return nil, ERR_UnexpectedContentType
	}

	return rv, nil
}

var hsbuf []byte = []byte{}

func NextHandshake(c net.Conn) (byte, []byte, error) {
	for len(hsbuf) < 4 {
		nb, err := ReadCapsule(c, 22)
		if err != nil {
			return 0, nil, err
		}
		hsbuf = append(hsbuf, nb...)
	}
	hstype := hsbuf[0]
	expected_length := int(hsbuf[1])<<16 | int(hsbuf[2])<<8 | int(hsbuf[3])
	for len(hsbuf) < expected_length+4 {
		nb, err := ReadCapsule(c, 22)
		if err != nil {
			return 0, nil, err
		}
		hsbuf = append(hsbuf, nb...)
	}

	rv := make([]byte, expected_length)
	copy(rv, hsbuf[4:4+expected_length])
	nb := make([]byte, len(hsbuf)-expected_length-4)
	copy(nb, hsbuf[4+expected_length:])
	hsbuf = nb
	return hstype, rv, nil
}
<commit_msg>Properly read a buffer until full<commit_after>package sslprobe

import (
	"crypto/rand"
	"fmt"
	"net"
)

func CipherPreference(host string, port int, version TLSVersion) []CipherInfo {
	maxl := len(AllCiphers)
	rv := make([]CipherInfo, maxl)
	copy(rv, AllCiphers)
	candidates := 0

	for candidates < maxl {
		ciph, vv, _ := Connect(host, port, version, rv[candidates:])
		if ciph.ID != 0x0000 && vv == version {
			for i, c := range rv {
				if i <= candidates {
					continue
				}
				if c.ID == ciph.ID {
					for j := i; j > candidates; j-- {
						rv[j] = rv[j-1]
					}
					rv[candidates] = ciph
					break
				}
			}
			candidates++
		} else {
			break
		}
	}
	return rv[0:candidates]
}

type supportedProtocol struct {
	Version   TLSVersion
	Supported bool
}

func SupportedProtocols(host string, port int) []supportedProtocol {
	rv := make([]supportedProtocol, 0, 6)
	all := []TLSVersion{SSL_2_0, SSL_3_0, TLS_1_0, TLS_1_1, TLS_1_2, TLS_1_3}

	for _, v := range all {
		cph, vv, _ := Connect(host, port, v, AllCiphers)
		rv = append(rv, supportedProtocol{v, cph.ID != 0x0000 && v == vv})
	}
	return rv
}

func Connect(host string, port int, version TLSVersion, ciphers []CipherInfo) (rv CipherInfo, tls_version TLSVersion, err error) {
	serverHello, _, _, err := HalfHandshake(host, port, version, ciphers)
	if err != nil {
		return
	}
	sess_l := int(serverHello[34])
	rv = IDCipher(uint16(serverHello[35+sess_l])<<8 | uint16(serverHello[36+sess_l]))
	tls_version = TLSVersion(uint16(serverHello[0])<<8 | uint16(serverHello[1]))
	return
}

func HalfHandshake(host string, port int, version TLSVersion, ciphers []CipherInfo) (serverHello, serverCertificate, serverKeyExchange []byte, err error) {
	var c net.Conn
	c, err = net.Dial("tcp", fmt.Sprintf("%s:%d", host, port))
	if err != nil {
		return
	}

	// Be polite - send a fatal alert before hanging up
	defer func() {
		c.Write([]byte{21, byte(uint(version) >> 8), byte(uint(version)), 0, 2, 2, 0})
		c.Close()
	}()

	serverName := []byte(host)
	extension_length := 2 + 2 + 2 + 3 + len(serverName)
	clienthello_length := 46 + 2*len(ciphers) + 2 + 2 + extension_length

	clientHello := make([]byte, clienthello_length)
	clientHello[0] = 22 // handshake
	pint2(clientHello[1:], int(version))
	pint2(clientHello[3:], clienthello_length-5)
	clientHello[5] = 1 // client_hello
	pint3(clientHello[6:], clienthello_length-9)
	pint2(clientHello[9:], int(version))
	rand.Read(clientHello[11:42])
	for j := 0; j < 32; j++ {
		clientHello[11+j] = byte((j%8 + 1) * 17)
	}
	clientHello[43] = 0 // Session ID length

	// Cipher List
	pint2(clientHello[44:], 2*len(ciphers))
	for i, c := range ciphers {
		pint2(clientHello[46+2*i:], int(c.ID))
	}
	idx := 46 + 2*len(ciphers)
	clientHello[idx+0] = 1 // Compression methods length
	clientHello[idx+1] = 0 // None

	idx += 2
	// Extensions
	pint2(clientHello[idx:], extension_length)

	// Server Name
	pint2(clientHello[idx+2:], 0) // server_name
	pint2(clientHello[idx+4:], 2+3+len(serverName))
	idx += 6
	pint2(clientHello[idx:], 3+len(serverName))
	idx += 2
	clientHello[idx] = 0
	pint2(clientHello[idx+1:], len(serverName))
	copy(clientHello[idx+3:], serverName)

	// fmt.Printf("%s", clientHello)
	//return

	_, err = c.Write(clientHello)
	if err != nil {
		return
	}

	hstype, serverHello, err := NextHandshake(c)
	if err != nil {
		serverHello = nil
		if alert, ok := err.(Alert); ok {
			// Ignore 'unrecognized name' warnings.
			if alert.Level == 1 && alert.Description == 112 {
				hstype, serverHello, err = NextHandshake(c)
				if err != nil {
					serverHello = nil
					return
				}
			} else {
				return
			}
		} else {
			return
		}
	}
	if hstype != 2 {
		serverHello = nil
		err = fmt.Errorf("Was expecting a ServerHello.")
		return
	}

	sess_l := int(serverHello[34])
	cipher := IDCipher(uint16(serverHello[35+sess_l])<<8 | uint16(serverHello[36+sess_l]))

	if cipher.Auth == AU_RSA || cipher.Auth == AU_DSA || cipher.Auth == AU_ECDSA {
		hstype, serverCertificate, err = NextHandshake(c)
		if err != nil {
			serverCertificate = nil
			return
		}
		if hstype != 11 {
			serverCertificate = nil
			err = fmt.Errorf("Was expecting a Certificate")
			return
		}
	}

	if cipher.Kex == KX_ECDHE || cipher.Kex == KX_FFDHE {
		hstype, serverKeyExchange, err = NextHandshake(c)
		if err != nil {
			serverKeyExchange = nil
			return
		}
		if hstype != 12 {
			serverKeyExchange = nil
			err = fmt.Errorf("Was expecting a ServerKeyExchange")
			return
		}
	}

	return
}

// Take a uint and stick it in the byte slice
func pint2(target []byte, source int) {
	target[0] = byte(source >> 8)
	target[1] = byte(source & 255)
}
func pint3(target []byte, source int) {
	target[0] = byte(source >> 16)
	target[1] = byte(source >> 8)
	target[2] = byte(source & 255)
}

var ERR_EncapsulationHeader error = fmt.Errorf("Unable to read encapsulation header")
var ERR_UnexpectedContentType error = fmt.Errorf("Unexpected ContentType")

func ReadCapsule(c net.Conn, expectedContentType byte) ([]byte, error) {
	lb := make([]byte, 5)
	n, err := c.Read(lb)
	if err != nil {
		return nil, err
	} else if n != 5 {
		return nil, ERR_EncapsulationHeader
	}

	length := (int(lb[3]) << 8) | int(lb[4])
	rv := make([]byte, length)
	s := 0
	n = 0
	for s < length {
		n, err = c.Read(rv[s:])
		if err != nil {
			return nil, err
		}
		s += n
	}

	if lb[0] == 21 {
		// This is a TLS alert, and therefore probably an error
		return nil, Alert{rv[0], rv[1]}
	} else if lb[0] != expectedContentType {
		return nil, ERR_UnexpectedContentType
	}

	return rv, nil
}

var hsbuf []byte = []byte{}

func NextHandshake(c net.Conn) (byte, []byte, error) {
	for len(hsbuf) < 4 {
		nb, err := ReadCapsule(c, 22)
		if err != nil {
			return 0, nil, err
		}
		hsbuf = append(hsbuf, nb...)
	}
	hstype := hsbuf[0]
	expected_length := int(hsbuf[1])<<16 | int(hsbuf[2])<<8 | int(hsbuf[3])
	for len(hsbuf) < expected_length+4 {
		nb, err := ReadCapsule(c, 22)
		if err != nil {
			return 0, nil, err
		}
		hsbuf = append(hsbuf, nb...)
	}

	rv := make([]byte, expected_length)
	copy(rv, hsbuf[4:4+expected_length])
	nb := make([]byte, len(hsbuf)-expected_length-4)
	copy(nb, hsbuf[4+expected_length:])
	hsbuf = nb
	return hstype, rv, nil
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"strings"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/protocol/go"
)

type CmdSigsList struct {
	filter  string
	revoked bool
	json    bool
	verbose bool
	allKeys bool
	headers bool
	types   map[string]bool

	username string

	user  *libkb.User
	sigs  []libkb.TypedChainLink
	ksigs []keybase1.Sig
}

func (s *CmdSigsList) ParseTypes(ctx *cli.Context) error {
	tmp := ctx.String("type")
	if len(tmp) == 0 {
		return nil
	}

	types := map[string]bool{
		"track":          true,
		"proof":          true,
		"cryptocurrency": true,
		"self":           true,
	}

	ret := make(map[string]bool)
	v := strings.Split(tmp, ",")
	for _, i := range v {
		ok, found := types[i]
		if !ok || !found {
			return fmt.Errorf("Unknown signature type: %s", i)
		}
		ret[i] = true
	}
	s.types = ret
	return nil
}

func (s *CmdSigsList) ParseArgv(ctx *cli.Context) error {
	nargs := len(ctx.Args())
	var err error

	s.revoked = ctx.Bool("revoked")
	s.json = ctx.Bool("json")
	s.verbose = ctx.Bool("verbose")
	s.allKeys = ctx.Bool("all-keys")
	s.headers = ctx.Bool("headers")
	s.filter = ctx.String("filter")

	if err = s.ParseTypes(ctx); err != nil {
		return err
	}

	if nargs == 1 {
		s.username = ctx.Args()[0]
	} else if nargs > 1 {
		err = fmt.Errorf("List takes at most 1 arg, a username.")
	}

	return err
}

func (s *CmdSigsList) DisplayKTable(sigs []keybase1.Sig) (err error) {
	if sigs == nil {
		return nil
	}

	var cols []string

	if s.headers {
		cols = []string{
			"#",
			"SigId",
			"Type",
			"Date",
		}
		if s.revoked {
			cols = append(cols, "Revoked")
		}
		if s.allKeys {
			cols = append(cols, "Active", "Key")
		}
		cols = append(cols, "Body")
	}

	i := 0

	rowfunc := func() []string {
		var row []string
		for ; i < len(sigs) && row == nil; i++ {
			link := sigs[i]
			row = []string{
				fmt.Sprintf("%d", link.Seqno),
				link.SigIDDisplay,
				link.Type,
				keybase1.FormatTime(link.CTime),
			}
			if s.revoked {
				var ch string
				if link.Revoked {
					ch = "R"
				} else {
					ch = "."
				}
				row = append(row, ch)
			}
			if s.allKeys {
				var ch string
				if link.Active {
					ch = "+"
				} else {
					ch = "-"
				}
				row = append(row, ch, link.Key)
			}
			row = append(row, link.Body)
		}
		return row
	}

	GlobUI.Tablify(cols, rowfunc)

	return
}

func (s *CmdSigsList) Run() error {
	cli, err := GetSigsClient()
	if err != nil {
		return err
	}
	var t *keybase1.SigTypes
	if s.types != nil {
		t = &keybase1.SigTypes{
			Track:          s.types["track"],
			Proof:          s.types["proof"],
			Cryptocurrency: s.types["cryptocurrency"],
			IsSelf:         s.types["self"],
		}
	}
	args := keybase1.SigListArgs{
		Username: s.username,
		AllKeys:  s.allKeys,
		Filterx:  s.filter,
		Verbose:  s.verbose,
		Revoked:  s.revoked,
		Types:    t,
	}

	if s.json {
		json, err := cli.SigListJSON(keybase1.SigListJSONArg{Arg: args})
		if err != nil {
			return err
		}
		GlobUI.Println(json)
		return nil
	}

	sigs, err := cli.SigList(keybase1.SigListArg{Arg: args})
	if err != nil {
		return err
	}
	return s.DisplayKTable(sigs)
}

func NewCmdSigsList(cl *libcmdline.CommandLine) cli.Command {
	return cli.Command{
		Name:  "list",
		Usage: "List signatures",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(&CmdSigsList{}, "list", c)
		},
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "r, revoked",
				Usage: "Show revoked signatures.",
			},
			cli.BoolFlag{
				Name:  "j, json",
				Usage: "Output as JSON (default is text).",
			},
			cli.BoolFlag{
				Name:  "v, verbose",
				Usage: "A full dump, with more gory details.",
			},
			cli.StringFlag{
				Name:  "t, type",
				Usage: "Type of sig to output: track, proof, cryptocurrency, self, all (default is all).",
			},
			cli.BoolFlag{
				Name:  "a, all-keys",
				Usage: "Show signatures from all (replaced) keys.",
			},
			cli.BoolFlag{
				Name:  "H, headers",
				Usage: "Show column headers.",
			},
			cli.StringFlag{
				Name:  "f, filter",
				Usage: "Provide a regex filter.",
			},
		},
	}
}

func (s *CmdSigsList) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config: true,
		API:    true,
	}
}
<commit_msg>Add ArgumentHelp for sigs list<commit_after>package client

import (
	"fmt"
	"strings"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/protocol/go"
)

type CmdSigsList struct {
	filter  string
	revoked bool
	json    bool
	verbose bool
	allKeys bool
	headers bool
	types   map[string]bool

	username string

	user  *libkb.User
	sigs  []libkb.TypedChainLink
	ksigs []keybase1.Sig
}

func (s *CmdSigsList) ParseTypes(ctx *cli.Context) error {
	tmp := ctx.String("type")
	if len(tmp) == 0 {
		return nil
	}

	types := map[string]bool{
		"track":          true,
		"proof":          true,
		"cryptocurrency": true,
		"self":           true,
	}

	ret := make(map[string]bool)
	v := strings.Split(tmp, ",")
	for _, i := range v {
		ok, found := types[i]
		if !ok || !found {
			return fmt.Errorf("Unknown signature type: %s", i)
		}
		ret[i] = true
	}
	s.types = ret
	return nil
}

func (s *CmdSigsList) ParseArgv(ctx *cli.Context) error {
	nargs := len(ctx.Args())
	var err error

	s.revoked = ctx.Bool("revoked")
	s.json = ctx.Bool("json")
	s.verbose = ctx.Bool("verbose")
	s.allKeys = ctx.Bool("all-keys")
	s.headers = ctx.Bool("headers")
	s.filter = ctx.String("filter")

	if err = s.ParseTypes(ctx); err != nil {
		return err
	}

	if nargs == 1 {
		s.username = ctx.Args()[0]
	} else if nargs > 1 {
		err = fmt.Errorf("List takes at most 1 arg, a username.")
	}

	return err
}

func (s *CmdSigsList) DisplayKTable(sigs []keybase1.Sig) (err error) {
	if sigs == nil {
		return nil
	}

	var cols []string

	if s.headers {
		cols = []string{
			"#",
			"SigId",
			"Type",
			"Date",
		}
		if s.revoked {
			cols = append(cols, "Revoked")
		}
		if s.allKeys {
			cols = append(cols, "Active", "Key")
		}
		cols = append(cols, "Body")
	}

	i := 0

	rowfunc := func() []string {
		var row []string
		for ; i < len(sigs) && row == nil; i++ {
			link := sigs[i]
			row = []string{
				fmt.Sprintf("%d", link.Seqno),
				link.SigIDDisplay,
				link.Type,
				keybase1.FormatTime(link.CTime),
			}
			if s.revoked {
				var ch string
				if link.Revoked {
					ch = "R"
				} else {
					ch = "."
				}
				row = append(row, ch)
			}
			if s.allKeys {
				var ch string
				if link.Active {
					ch = "+"
				} else {
					ch = "-"
				}
				row = append(row, ch, link.Key)
			}
			row = append(row, link.Body)
		}
		return row
	}

	GlobUI.Tablify(cols, rowfunc)

	return
}

func (s *CmdSigsList) Run() error {
	cli, err := GetSigsClient()
	if err != nil {
		return err
	}
	var t *keybase1.SigTypes
	if s.types != nil {
		t = &keybase1.SigTypes{
			Track:          s.types["track"],
			Proof:          s.types["proof"],
			Cryptocurrency: s.types["cryptocurrency"],
			IsSelf:         s.types["self"],
		}
	}
	args := keybase1.SigListArgs{
		Username: s.username,
		AllKeys:  s.allKeys,
		Filterx:  s.filter,
		Verbose:  s.verbose,
		Revoked:  s.revoked,
		Types:    t,
	}

	if s.json {
		json, err := cli.SigListJSON(keybase1.SigListJSONArg{Arg: args})
		if err != nil {
			return err
		}
		GlobUI.Println(json)
		return nil
	}

	sigs, err := cli.SigList(keybase1.SigListArg{Arg: args})
	if err != nil {
		return err
	}
	return s.DisplayKTable(sigs)
}

func NewCmdSigsList(cl *libcmdline.CommandLine) cli.Command {
	return cli.Command{
		Name:         "list",
		Usage:        "List signatures",
		ArgumentHelp: "[username]",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(&CmdSigsList{}, "list", c)
		},
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "r, revoked",
				Usage: "Show revoked signatures.",
			},
			cli.BoolFlag{
				Name:  "j, json",
				Usage: "Output as JSON (default is text).",
			},
			cli.BoolFlag{
				Name:  "v, verbose",
				Usage: "A full dump, with more gory details.",
			},
			cli.StringFlag{
				Name:  "t, type",
				Usage: "Type of sig to output: track, proof, cryptocurrency, self, all (default is all).",
			},
			cli.BoolFlag{
				Name:  "a, all-keys",
				Usage: "Show signatures from all (replaced) keys.",
			},
			cli.BoolFlag{
				Name:  "H, headers",
				Usage: "Show column headers.",
			},
			cli.StringFlag{
				Name:  "f, filter",
				Usage: "Provide a regex filter.",
			},
		},
	}
}

func (s *CmdSigsList) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config: true,
		API:    true,
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package engine

import (
	"fmt"
	"sort"
	"strings"
	"testing"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

func TestFavoriteAdd(t *testing.T) {
	tc := SetupEngineTest(t, "template")
	defer tc.Cleanup()
	u := CreateAndSignupFakeUser(tc, "fav")
	expectedFaves := newFavorites(u.Username)

	idUI := &FakeIdentifyUI{}
	addfav("t_alice,t_bob", true, true, idUI, tc, expectedFaves)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}

	// Add the same share again. The number shouldn't change.
	addfav("t_alice,t_bob", true, true, idUI, tc, nil)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}

	// Add a public share of the same name, make sure both are represented.
	addfav("t_alice,t_bob", false, true, idUI, tc, expectedFaves)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}
}

// Test adding a favorite with a social assertion.
// Sharing before signup, social assertion user doesn't
// exist yet.
func TestFavoriteAddSocial(t *testing.T) {
	tc := SetupEngineTest(t, "template")
	defer tc.Cleanup()
	u := CreateAndSignupFakeUser(tc, "fav")
	expectedFaves := newFavorites(u.Username)

	idUI := &FakeIdentifyUI{}
	addfav(fmt.Sprintf("bob@twitter,%s", u.Username), true, true, idUI, tc, expectedFaves)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}

	if idUI.DisplayTLFCount != 1 {
		t.Errorf("DisplayTLFCount: %d, expected 1", idUI.DisplayTLFCount)
	}
	// There's no way to give invites to a user via API, so the
	// only case we can test automatically is the user being
	// out of invites.
	if !idUI.DisplayTLFArg.Throttled {
		t.Errorf("DisplayTLFArg.Throttled not set, expected it to be since user has no invites.")
	}
	if !idUI.DisplayTLFArg.IsPrivate {
		t.Errorf("DisplayTLFArg.IsPrivate not set on a private folder")
	}

	idUI = &FakeIdentifyUI{}
	// Test adding a favorite when not the creator.  Should not call ui for
	// displaying tlf + invite.
	// created flag == false
	addfav(fmt.Sprintf("bobdog@twitter,%s", u.Username), true, false, idUI, tc, expectedFaves)
	if newFaves := listfav(tc); !newFaves.Equal(*expectedFaves) {
		t.Errorf("bad favorites: %s != %s", newFaves, expectedFaves)
	}
	if idUI.DisplayTLFCount != 0 {
		t.Errorf("DisplayTLFCount: %d, expected 0", idUI.DisplayTLFCount)
	}

	idUI = &FakeIdentifyUI{}
	// Make sure ui for displaying tlf + invite not called for non-social
	// assertion TLF.
	addfav(fmt.Sprintf("%s,t_alice", u.Username), true, true, idUI, tc, expectedFaves)
	if newFaves := listfav(tc); !newFaves.Equal(*expectedFaves) {
		t.Errorf("bad favorites: %s != %s", newFaves, expectedFaves)
	}
	if idUI.DisplayTLFCount != 0 {
		t.Errorf("DisplayTLFCount: %d, expected 0", idUI.DisplayTLFCount)
	}

	idUI = &FakeIdentifyUI{}
	// Test adding a public favorite with SBS social assertion
	addfav(fmt.Sprintf("bobdog@twitter,%s", u.Username), false, true, idUI, tc, expectedFaves)
	if newFaves := listfav(tc); !newFaves.Equal(*expectedFaves) {
		t.Errorf("bad favorites: %s != %s", newFaves, expectedFaves)
	}
	if idUI.DisplayTLFCount != 1 {
		t.Errorf("DisplayTLFCount: %d, expected 1", idUI.DisplayTLFCount)
	}
	if idUI.DisplayTLFArg.IsPrivate {
		t.Errorf("DisplayTLFArg.IsPrivate set on a public folder")
	}
}

func TestFavoriteIgnore(t *testing.T) {
	tc := SetupEngineTest(t, "template")
	defer tc.Cleanup()
	u := CreateAndSignupFakeUser(tc, "fav")

	expectedFaves := newFavorites(u.Username)

	idUI := &FakeIdentifyUI{}
	addfav("t_alice,t_bob", true, true, idUI, tc, expectedFaves)
	addfav("t_alice,t_charlie", true, true, idUI, tc, expectedFaves)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}
	rmfav("t_alice,t_bob", true, tc, expectedFaves)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}
}

func TestFavoriteList(t *testing.T) {
	tc := SetupEngineTest(t, "template")
	defer tc.Cleanup()
	u := CreateAndSignupFakeUser(tc, "fav")
	expectedFaves := newFavorites(u.Username)

	idUI := &FakeIdentifyUI{}
	addfav("t_alice,t_charlie", true, true, idUI, tc, expectedFaves)
	addfav("t_alice,t_bob", true, true, idUI, tc, expectedFaves)

	ctx := &Context{}
	eng := NewFavoriteList(tc.G)
	if err := RunEngine(eng, ctx); err != nil {
		t.Fatal(err)
	}
	favs := eng.Result().FavoriteFolders
	if !newFavoritesFromServer(favs).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}
}

func addfav(name string, private, created bool, idUI libkb.IdentifyUI, tc libkb.TestContext, expectedFaves *favorites) {
	ctx := &Context{
		IdentifyUI: idUI,
	}
	arg := keybase1.FavoriteAddArg{
		Folder: keybase1.Folder{Name: name, Private: private, Created: created},
	}
	eng := NewFavoriteAdd(&arg, tc.G)
	err := RunEngine(eng, ctx)
	if err != nil {
		tc.T.Fatal(err)
	}
	eng.Wait()
	if expectedFaves != nil {
		expectedFaves.Push(keybase1.Folder{Name: name, Private: private})
	}
}

func rmfav(name string, private bool, tc libkb.TestContext, expectedFaves *favorites) {
	ctx := &Context{}
	arg := keybase1.FavoriteIgnoreArg{
		Folder: keybase1.Folder{Name: name, Private: private},
	}
	eng := NewFavoriteIgnore(&arg, tc.G)
	err := RunEngine(eng, ctx)
	if err != nil {
		tc.T.Fatal(err)
	}
	if expectedFaves != nil {
		expectedFaves.Remove(keybase1.Folder{Name: name, Private: private})
	}
}

func listfav(tc libkb.TestContext) *favorites {
	ctx := &Context{}
	eng := NewFavoriteList(tc.G)
	err := RunEngine(eng, ctx)
	if err != nil {
		tc.T.Fatal(err)
	}
	return newFavoritesFromServer(eng.Result().FavoriteFolders)
}

type favorites struct {
	m map[string]bool
}

func newFavorites(un string) *favorites {
	ret := &favorites{
		m: make(map[string]bool),
	}
	for _, f := range defaultFaves(un) {
		ret.Push(f)
	}
	return ret
}

func newFavoritesFromServer(v []keybase1.Folder) *favorites {
	ret := &favorites{
		m: make(map[string]bool),
	}
	for _, f := range v {
		ret.Push(f)
	}
	return ret
}

func (v *favorites) Push(f keybase1.Folder) {
	k := makeKey(f)
	if !v.m[k] {
		v.m[k] = true
	}
}

func (v *favorites) Remove(f keybase1.Folder) {
	delete(v.m, makeKey(f))
}

func (v favorites) Equal(b favorites) bool {
	for k := range v.m {
		if !b.m[k] {
			return false
		}
	}
	for k := range b.m {
		if !v.m[k] {
			return false
		}
	}
	return true
}

func makeKey(f keybase1.Folder) string {
	return fmt.Sprintf("%s:%v", f.Name, f.Private)
}

func defaultFaves(un string) []keybase1.Folder {
	return []keybase1.Folder{
		keybase1.Folder{Name: un, Private: false},
		keybase1.Folder{Name: un, Private: true},
	}
}

func (v *favorites) String() string {
	var s []string
	for f := range v.m {
		s = append(s, f)
	}
	sort.Strings(s)
	return strings.Join(s, ";")
}
<commit_msg>disable tests that depended on broken behavior<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package engine

import (
	"fmt"
	"sort"
	"strings"
	"testing"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

func TestFavoriteAdd(t *testing.T) {
	t.Skip()
	tc := SetupEngineTest(t, "template")
	defer tc.Cleanup()
	u := CreateAndSignupFakeUser(tc, "fav")
	expectedFaves := newFavorites(u.Username)

	idUI := &FakeIdentifyUI{}
	addfav("t_alice,t_bob", true, true, idUI, tc, expectedFaves)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}

	// Add the same share again. The number shouldn't change.
	addfav("t_alice,t_bob", true, true, idUI, tc, nil)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}

	// Add a public share of the same name, make sure both are represented.
	addfav("t_alice,t_bob", false, true, idUI, tc, expectedFaves)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}
}

// Test adding a favorite with a social assertion.
// Sharing before signup, social assertion user doesn't
// exist yet.
func TestFavoriteAddSocial(t *testing.T) {
	t.Skip()
	tc := SetupEngineTest(t, "template")
	defer tc.Cleanup()
	u := CreateAndSignupFakeUser(tc, "fav")
	expectedFaves := newFavorites(u.Username)

	idUI := &FakeIdentifyUI{}
	addfav(fmt.Sprintf("bob@twitter,%s", u.Username), true, true, idUI, tc, expectedFaves)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}

	if idUI.DisplayTLFCount != 1 {
		t.Errorf("DisplayTLFCount: %d, expected 1", idUI.DisplayTLFCount)
	}
	// There's no way to give invites to a user via API, so the
	// only case we can test automatically is the user being
	// out of invites.
	if !idUI.DisplayTLFArg.Throttled {
		t.Errorf("DisplayTLFArg.Throttled not set, expected it to be since user has no invites.")
	}
	if !idUI.DisplayTLFArg.IsPrivate {
		t.Errorf("DisplayTLFArg.IsPrivate not set on a private folder")
	}

	idUI = &FakeIdentifyUI{}
	// Test adding a favorite when not the creator.  Should not call ui for
	// displaying tlf + invite.
	// created flag == false
	addfav(fmt.Sprintf("bobdog@twitter,%s", u.Username), true, false, idUI, tc, expectedFaves)
	if newFaves := listfav(tc); !newFaves.Equal(*expectedFaves) {
		t.Errorf("bad favorites: %s != %s", newFaves, expectedFaves)
	}
	if idUI.DisplayTLFCount != 0 {
		t.Errorf("DisplayTLFCount: %d, expected 0", idUI.DisplayTLFCount)
	}

	idUI = &FakeIdentifyUI{}
	// Make sure ui for displaying tlf + invite not called for non-social
	// assertion TLF.
	addfav(fmt.Sprintf("%s,t_alice", u.Username), true, true, idUI, tc, expectedFaves)
	if newFaves := listfav(tc); !newFaves.Equal(*expectedFaves) {
		t.Errorf("bad favorites: %s != %s", newFaves, expectedFaves)
	}
	if idUI.DisplayTLFCount != 0 {
		t.Errorf("DisplayTLFCount: %d, expected 0", idUI.DisplayTLFCount)
	}

	idUI = &FakeIdentifyUI{}
	// Test adding a public favorite with SBS social assertion
	addfav(fmt.Sprintf("bobdog@twitter,%s", u.Username), false, true, idUI, tc, expectedFaves)
	if newFaves := listfav(tc); !newFaves.Equal(*expectedFaves) {
		t.Errorf("bad favorites: %s != %s", newFaves, expectedFaves)
	}
	if idUI.DisplayTLFCount != 1 {
		t.Errorf("DisplayTLFCount: %d, expected 1", idUI.DisplayTLFCount)
	}
	if idUI.DisplayTLFArg.IsPrivate {
		t.Errorf("DisplayTLFArg.IsPrivate set on a public folder")
	}
}

func TestFavoriteIgnore(t *testing.T) {
	t.Skip()
	tc := SetupEngineTest(t, "template")
	defer tc.Cleanup()
	u := CreateAndSignupFakeUser(tc, "fav")

	expectedFaves := newFavorites(u.Username)

	idUI := &FakeIdentifyUI{}
	addfav("t_alice,t_bob", true, true, idUI, tc, expectedFaves)
	addfav("t_alice,t_charlie", true, true, idUI, tc, expectedFaves)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}
	rmfav("t_alice,t_bob", true, tc, expectedFaves)
	if !listfav(tc).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}
}

func TestFavoriteList(t *testing.T) {
	t.Skip()
	tc := SetupEngineTest(t, "template")
	defer tc.Cleanup()
	u := CreateAndSignupFakeUser(tc, "fav")
	expectedFaves := newFavorites(u.Username)

	idUI := &FakeIdentifyUI{}
	addfav("t_alice,t_charlie", true, true, idUI, tc, expectedFaves)
	addfav("t_alice,t_bob", true, true, idUI, tc, expectedFaves)

	ctx := &Context{}
	eng := NewFavoriteList(tc.G)
	if err := RunEngine(eng, ctx); err != nil {
		t.Fatal(err)
	}
	favs := eng.Result().FavoriteFolders
	if !newFavoritesFromServer(favs).Equal(*expectedFaves) {
		t.Errorf("bad favorites")
	}
}

func addfav(name string, private, created bool, idUI libkb.IdentifyUI, tc libkb.TestContext, expectedFaves *favorites) {
	ctx := &Context{
		IdentifyUI: idUI,
	}
	arg := keybase1.FavoriteAddArg{
		Folder: keybase1.Folder{Name: name, Private: private, Created: created},
	}
	eng := NewFavoriteAdd(&arg, tc.G)
	err := RunEngine(eng, ctx)
	if err != nil {
		tc.T.Fatal(err)
	}
	eng.Wait()
	if expectedFaves != nil {
		expectedFaves.Push(keybase1.Folder{Name: name, Private: private})
	}
}

func rmfav(name string, private bool, tc libkb.TestContext, expectedFaves *favorites) {
	ctx := &Context{}
	arg := keybase1.FavoriteIgnoreArg{
		Folder: keybase1.Folder{Name: name, Private: private},
	}
	eng := NewFavoriteIgnore(&arg, tc.G)
	err := RunEngine(eng, ctx)
	if err != nil {
		tc.T.Fatal(err)
	}
	if expectedFaves != nil {
		expectedFaves.Remove(keybase1.Folder{Name: name, Private: private})
	}
}

func listfav(tc libkb.TestContext) *favorites {
	ctx := &Context{}
	eng := NewFavoriteList(tc.G)
	err := RunEngine(eng, ctx)
	if err != nil {
		tc.T.Fatal(err)
	}
	return newFavoritesFromServer(eng.Result().FavoriteFolders)
}

type favorites struct {
	m map[string]bool
}

func newFavorites(un string) *favorites {
	ret := &favorites{
		m: make(map[string]bool),
	}
	for _, f := range defaultFaves(un) {
		ret.Push(f)
	}
	return ret
}

func newFavoritesFromServer(v []keybase1.Folder) *favorites {
	ret := &favorites{
		m: make(map[string]bool),
	}
	for _, f := range v {
		ret.Push(f)
	}
	return ret
}

func (v *favorites) Push(f keybase1.Folder) {
	k := makeKey(f)
	if !v.m[k] {
		v.m[k] = true
	}
}

func (v *favorites) Remove(f keybase1.Folder) {
	delete(v.m, makeKey(f))
}

func (v favorites) Equal(b favorites) bool {
	for k := range v.m {
		if !b.m[k] {
			return false
		}
	}
	for k := range b.m {
		if !v.m[k] {
			return false
		}
	}
	return true
}

func makeKey(f keybase1.Folder) string {
	return fmt.Sprintf("%s:%v", f.Name, f.Private)
}

func defaultFaves(un string) []keybase1.Folder {
	return []keybase1.Folder{
		keybase1.Folder{Name: un, Private: false},
		keybase1.Folder{Name: un, Private: true},
	}
}

func (v *favorites) String() string {
	var s []string
	for f := range v.m {
		s = append(s, f)
	}
	sort.Strings(s)
	return strings.Join(s, ";")
}
<|endoftext|>


<commit_before>package libkb

import (
	"encoding/hex"
	"math/rand"
	"sync"
	"testing"

	keybase1 "github.com/keybase/client/protocol/go"
)

func TestConcurrentUserCache(t *testing.T) {
	uc, err := NewUserCache(10000)
	if err != nil {
		t.Fatal(err)
	}
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			for j := 0; j < 100; j++ {
				uid := UsernameToUID(randomString())
				u := &User{id: uid}
				// nlock doesn't really matter in this situation, but
				// code using usercache holds it during Put(), so
				// putting it here too.
				nlock := uc.LockUID(uid.String())
				uc.Put(u)
				nlock.Unlock()
			}
			wg.Done()
		}()
		wg.Add(1)
		go func() {
			for j := 0; j < 100; j++ {
				x, err := RandBytes(UID_LEN)
				if err != nil {
					t.Fatal(err)
				}
				u, _ := keybase1.UIDFromString(hex.EncodeToString(x))
				// nlock doesn't really matter, but code using
				// usercache holds it during Get(), so putting it here too.
				nlock := uc.LockUID(u.String())
				uc.Get(u)
				nlock.Unlock()
			}
			wg.Done()
		}()
	}

	wg.Wait()
}

// just for testing
func randomString() string {
	numChars := rand.Intn(50)
	codePoints := make([]rune, numChars)
	for i := 0; i < numChars; i++ {
		codePoints[i] = rune(rand.Intn(0x10ffff))
	}
	return string(codePoints)
}
<commit_msg>fixed test<commit_after>package libkb

import (
	"encoding/hex"
	"math/rand"
	"sync"
	"testing"

	keybase1 "github.com/keybase/client/protocol/go"
)

func TestConcurrentUserCache(t *testing.T) {
	uc, err := NewUserCache(10000)
	if err != nil {
		t.Fatal(err)
	}
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			for j := 0; j < 100; j++ {
				uid := UsernameToUID(randomString())
				u := &User{id: uid}
				// nlock doesn't really matter in this situation, but
				// code using usercache holds it during Put(), so
				// putting it here too.
				nlock := uc.LockUID(uid.String())
				uc.Put(u)
				nlock.Unlock()
			}
			wg.Done()
		}()
		wg.Add(1)
		go func() {
			for j := 0; j < 100; j++ {
				x, err := RandBytes(keybase1.UID_LEN)
				if err != nil {
					t.Fatal(err)
				}
				u, _ := keybase1.UIDFromString(hex.EncodeToString(x))
				// nlock doesn't really matter, but code using
				// usercache holds it during Get(), so putting it here too.
				nlock := uc.LockUID(u.String())
				uc.Get(u)
				nlock.Unlock()
			}
			wg.Done()
		}()
	}

	wg.Wait()
}

// just for testing
func randomString() string {
	numChars := rand.Intn(50)
	codePoints := make([]rune, numChars)
	for i := 0; i < numChars; i++ {
		codePoints[i] = rune(rand.Intn(0x10ffff))
	}
	return string(codePoints)
}
<|endoftext|>


<commit_before>// Copyright 2017 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

// Handlers for team-related gregor messages

package service

import (
	"encoding/json"
	"fmt"
	"strings"
	"sync"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/badges"
	"github.com/keybase/client/go/gregor"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/gregor1"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/teams"
)

const teamHandlerName = "teamHandler"

type teamHandler struct {
	libkb.Contextified
	badger *badges.Badger

	teamRotateLock sync.Mutex // work on one rotation at a time
}

var _ libkb.GregorInBandMessageHandler = (*teamHandler)(nil)

func newTeamHandler(g *libkb.GlobalContext, badger *badges.Badger) *teamHandler {
	return &teamHandler{
		Contextified: libkb.NewContextified(g),
		badger:       badger,
	}
}

func (r *teamHandler) Create(ctx context.Context, cli gregor1.IncomingInterface, category string, item gregor.Item) (bool, error) {
	switch category {
	case "team.clkr":
		return true, r.rotateTeam(ctx, cli, item)
	case "team.sbs":
		return true, r.sharingBeforeSignup(ctx, cli, item)
	case "team.openreq":
		return true, r.openTeamAccessRequest(ctx, cli, item)
	case "team.change":
		return true, r.changeTeam(ctx, cli, item, keybase1.TeamChangeSet{})
	case "team.rename":
		return true, r.changeTeam(ctx, cli, item, keybase1.TeamChangeSet{Renamed: true})
	case "team.delete":
		return true, r.deleteTeam(ctx, cli, item)
	case "team.exit":
		return true, r.exitTeam(ctx, cli, item)
	case "team.seitan":
		return true, r.seitanCompletion(ctx, cli, item)
	case "team.member_out_from_reset":
		return true, r.memberOutFromReset(ctx, cli, item)
	case "team.abandoned":
		return true, r.abandonTeam(ctx, cli, item)
	default:
		if strings.HasPrefix(category, "team.") {
			return false, fmt.Errorf("unknown teamHandler category: %q", category)
		}
		return false, nil
	}
}

func (r *teamHandler) rotateTeam(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	r.G().Log.CDebugf(ctx, "teamHandler: team.clkr received")
	var msg keybase1.TeamCLKRMsg
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.clkr item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "team.clkr unmarshaled: %+v", msg)

	for _, uv := range msg.ResetUsersUntrusted {
		// We don't use UIDMapper in HandleRotateRequest, but since
		// server just told us that these users have reset, we might
		// as well use that knowledge to refresh cache.

		// Use ClearUIDAtEldestSeqno instead of InformOfEldestSeqno
		// because usually uv.UserEldestSeqno (the "new EldestSeqno")
		// will be 0, because user has just reset and hasn't
		// reprovisioned yet

		r.G().UIDMapper.ClearUIDAtEldestSeqno(ctx, r.G(), uv.Uid, uv.MemberEldestSeqno)
	}

	go func() {
		r.teamRotateLock.Lock()
		defer r.teamRotateLock.Unlock()

		if err := teams.HandleRotateRequest(ctx, r.G(), msg); err != nil {
			r.G().Log.CDebugf(ctx, "HandleRotateRequest failed with error: %s", err)
			return
		}

		r.G().Log.CDebugf(ctx, "dismissing team.clkr item since rotate succeeded")
		r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
	}()

	return nil
}

func (r *teamHandler) memberOutFromReset(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	nm := "team.member_out_from_reset"
	r.G().Log.CDebugf(ctx, "teamHandler: %s received", nm)
	var msg keybase1.TeamMemberOutFromReset
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling %s item: %s", nm, err)
		return err
	}
	r.G().Log.CDebugf(ctx, "%s unmarshaled: %+v", nm, msg)

	if err := r.G().UIDMapper.ClearUIDAtEldestSeqno(ctx, r.G(), msg.ResetUser.Uid, msg.ResetUser.EldestSeqno); err != nil {
		return err
	}

	r.G().Log.CDebugf(ctx, "%s: cleared UIDMap cache for %s%%%d", nm, msg.ResetUser.Uid, msg.ResetUser.EldestSeqno)
	return nil
}

type abandonMsg struct {
	TeamID keybase1.TeamID `json:"team_id"`
}

func (r *teamHandler) abandonTeam(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	nm := "team.abandoned"
	r.G().Log.CDebugf(ctx, "teamHandler.abandonTeam: %s received", nm)
	var msg abandonMsg
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling %s item: %s", nm, err)
		return err
	}
	r.G().Log.CDebugf(ctx, "teamHandler.abandonTeam: %s unmarshaled: %+v", nm, msg)

	r.G().NotifyRouter.HandleTeamAbandoned(ctx, msg.TeamID)

	r.G().Log.CDebugf(ctx, "teamHandler.abandonTeam: locally dismissing %s", nm)
	if err := r.G().GregorDismisser.LocalDismissItem(ctx, item.Metadata().MsgID()); err != nil {
		r.G().Log.CDebugf(ctx, "teamHandler.abandonTeam: failed to locally dismiss msg %v", item.Metadata().MsgID())
	}

	return nil
}

func (r *teamHandler) changeTeam(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item, changes keybase1.TeamChangeSet) error {
	var rows []keybase1.TeamChangeRow
	r.G().Log.CDebugf(ctx, "teamHandler: changeTeam received")
	if err := json.Unmarshal(item.Body().Bytes(), &rows); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.(change|rename) item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "team.(change|rename) unmarshaled: %+v", rows)
	if err := teams.HandleChangeNotification(ctx, r.G(), rows, changes); err != nil {
		return err
	}

	// Locally dismiss this now that we have processed it so we can avoid replaying it over and over
	if err := r.G().GregorDismisser.LocalDismissItem(ctx, item.Metadata().MsgID()); err != nil {
		r.G().Log.CDebugf(ctx, "failed to local dismiss team change: %s", err)
	}

	// check the badge state to see if any team reset badges need dismissal
	for _, row := range rows {
		badges := r.badger.State().FindResetMemberBadges(row.Name)

		if len(badges) == 0 {
			continue
		}

		// load this team and see if any of the badge users are active members
		details, err := teams.Details(ctx, r.G(), row.Name, false)
		if err != nil {
			r.G().Log.CDebugf(ctx, "error getting team details: %s", err)
			// not fatal
			continue
		}

		activeUsernames := details.Members.ActiveUsernames()

		for _, badge := range badges {
			active, inTeam := activeUsernames[badge.Username]
			if !inTeam {
				// the user is not in the team anymore, so dismiss the
				// gregor message for this badge
				r.G().Log.CDebugf(ctx, "user %s is not in team %s, dismissing TeamMemberOutFromReset badge", badge.Username, row.Name)
				if err := r.G().GregorDismisser.DismissItem(ctx, cli, badge.Id); err != nil {
					r.G().Log.CDebugf(ctx, "failed to dismiss TeamMemberOutFromReset badge: %s", err)
				}
			} else if active {
				// the user is active in the team, so dismiss the gregor message
				// for this badge
				r.G().Log.CDebugf(ctx, "user %s is active in team %s, dismissing TeamMemberOutFromReset badge", badge.Username, row.Name)
				if err := r.G().GregorDismisser.DismissItem(ctx, cli, badge.Id); err != nil {
					r.G().Log.CDebugf(ctx, "failed to dismiss TeamMemberOutFromReset badge: %s", err)
				}
			}
		}
	}

	return nil
}

func (r *teamHandler) deleteTeam(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	var rows []keybase1.TeamChangeRow
	if err := json.Unmarshal(item.Body().Bytes(), &rows); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.(change|rename) item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "teamHandler: team.delete unmarshaled: %+v", rows)

	err := teams.HandleDeleteNotification(ctx, r.G(), rows)
	if err != nil {
		return err
	}

	return r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
}

func (r *teamHandler) exitTeam(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	var rows []keybase1.TeamExitRow
	if err := json.Unmarshal(item.Body().Bytes(), &rows); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.exit item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "teamHandler: team.exit unmarshaled: %+v", rows)
	err := teams.HandleExitNotification(ctx, r.G(), rows)
	if err != nil {
		return err
	}

	r.G().Log.Debug("dismissing team.exit: %v", item.Metadata().MsgID().String())
	return r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
}

func (r *teamHandler) sharingBeforeSignup(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	r.G().Log.CDebugf(ctx, "teamHandler: team.sbs received")
	var msg keybase1.TeamSBSMsg
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.sbs item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "team.sbs unmarshaled: %+v", msg)

	if err := teams.HandleSBSRequest(ctx, r.G(), msg); err != nil {
		return err
	}

	r.G().Log.Debug("dismissing team.sbs item since it succeeded")
	return r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
}

func (r *teamHandler) openTeamAccessRequest(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	r.G().Log.CDebugf(ctx, "teamHandler: team.openreq received")
	var msg keybase1.TeamOpenReqMsg
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.openreq item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "team.openreq unmarshaled: %+v", msg)

	if err := teams.HandleOpenTeamAccessRequest(ctx, r.G(), msg); err != nil {
		return err
	}

	r.G().Log.CDebugf(ctx, "dismissing team.openreq item since it succeeded")
	return r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
}

func (r *teamHandler) seitanCompletion(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	r.G().Log.CDebugf(ctx, "teamHandler: team.seitan received")
	var msg keybase1.TeamSeitanMsg
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.seitan item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "team.seitan unmarshaled: %+v", msg)

	if err := teams.HandleTeamSeitan(ctx, r.G(), msg); err != nil {
		return err
	}

	r.G().Log.CDebugf(ctx, "dismissing team.seitan item since it succeeded")
	return r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
}

func (r *teamHandler) Dismiss(ctx context.Context, cli gregor1.IncomingInterface, category string, item gregor.Item) (bool, error) {
	return false, nil
}

func (r *teamHandler) IsAlive() bool {
	return true
}

func (r *teamHandler) Name() string {
	return teamHandlerName
}
<commit_msg>just ignore these in team gregor handler (#11748)<commit_after>// Copyright 2017 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

// Handlers for team-related gregor messages

package service

import (
	"encoding/json"
	"fmt"
	"strings"
	"sync"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/badges"
	"github.com/keybase/client/go/gregor"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/gregor1"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/teams"
)

const teamHandlerName = "teamHandler"

type teamHandler struct {
	libkb.Contextified
	badger *badges.Badger

	teamRotateLock sync.Mutex // work on one rotation at a time
}

var _ libkb.GregorInBandMessageHandler = (*teamHandler)(nil)

func newTeamHandler(g *libkb.GlobalContext, badger *badges.Badger) *teamHandler {
	return &teamHandler{
		Contextified: libkb.NewContextified(g),
		badger:       badger,
	}
}

func (r *teamHandler) Create(ctx context.Context, cli gregor1.IncomingInterface, category string, item gregor.Item) (bool, error) {
	switch category {
	case "team.clkr":
		return true, r.rotateTeam(ctx, cli, item)
	case "team.sbs":
		return true, r.sharingBeforeSignup(ctx, cli, item)
	case "team.openreq":
		return true, r.openTeamAccessRequest(ctx, cli, item)
	case "team.change":
		return true, r.changeTeam(ctx, cli, item, keybase1.TeamChangeSet{})
	case "team.rename":
		return true, r.changeTeam(ctx, cli, item, keybase1.TeamChangeSet{Renamed: true})
	case "team.delete":
		return true, r.deleteTeam(ctx, cli, item)
	case "team.exit":
		return true, r.exitTeam(ctx, cli, item)
	case "team.seitan":
		return true, r.seitanCompletion(ctx, cli, item)
	case "team.member_out_from_reset":
		return true, r.memberOutFromReset(ctx, cli, item)
	case "team.abandoned":
		return true, r.abandonTeam(ctx, cli, item)
	case "team.newly_added_to_team":
		return true, nil
	default:
		if strings.HasPrefix(category, "team.") {
			return false, fmt.Errorf("unknown teamHandler category: %q", category)
		}
		return false, nil
	}
}

func (r *teamHandler) rotateTeam(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	r.G().Log.CDebugf(ctx, "teamHandler: team.clkr received")
	var msg keybase1.TeamCLKRMsg
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.clkr item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "team.clkr unmarshaled: %+v", msg)

	for _, uv := range msg.ResetUsersUntrusted {
		// We don't use UIDMapper in HandleRotateRequest, but since
		// server just told us that these users have reset, we might
		// as well use that knowledge to refresh cache.

		// Use ClearUIDAtEldestSeqno instead of InformOfEldestSeqno
		// because usually uv.UserEldestSeqno (the "new EldestSeqno")
		// will be 0, because user has just reset and hasn't
		// reprovisioned yet

		r.G().UIDMapper.ClearUIDAtEldestSeqno(ctx, r.G(), uv.Uid, uv.MemberEldestSeqno)
	}

	go func() {
		r.teamRotateLock.Lock()
		defer r.teamRotateLock.Unlock()

		if err := teams.HandleRotateRequest(ctx, r.G(), msg); err != nil {
			r.G().Log.CDebugf(ctx, "HandleRotateRequest failed with error: %s", err)
			return
		}

		r.G().Log.CDebugf(ctx, "dismissing team.clkr item since rotate succeeded")
		r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
	}()

	return nil
}

func (r *teamHandler) memberOutFromReset(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	nm := "team.member_out_from_reset"
	r.G().Log.CDebugf(ctx, "teamHandler: %s received", nm)
	var msg keybase1.TeamMemberOutFromReset
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling %s item: %s", nm, err)
		return err
	}
	r.G().Log.CDebugf(ctx, "%s unmarshaled: %+v", nm, msg)

	if err := r.G().UIDMapper.ClearUIDAtEldestSeqno(ctx, r.G(), msg.ResetUser.Uid, msg.ResetUser.EldestSeqno); err != nil {
		return err
	}

	r.G().Log.CDebugf(ctx, "%s: cleared UIDMap cache for %s%%%d", nm, msg.ResetUser.Uid, msg.ResetUser.EldestSeqno)
	return nil
}

type abandonMsg struct {
	TeamID keybase1.TeamID `json:"team_id"`
}

func (r *teamHandler) abandonTeam(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	nm := "team.abandoned"
	r.G().Log.CDebugf(ctx, "teamHandler.abandonTeam: %s received", nm)
	var msg abandonMsg
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling %s item: %s", nm, err)
		return err
	}
	r.G().Log.CDebugf(ctx, "teamHandler.abandonTeam: %s unmarshaled: %+v", nm, msg)

	r.G().NotifyRouter.HandleTeamAbandoned(ctx, msg.TeamID)

	r.G().Log.CDebugf(ctx, "teamHandler.abandonTeam: locally dismissing %s", nm)
	if err := r.G().GregorDismisser.LocalDismissItem(ctx, item.Metadata().MsgID()); err != nil {
		r.G().Log.CDebugf(ctx, "teamHandler.abandonTeam: failed to locally dismiss msg %v", item.Metadata().MsgID())
	}

	return nil
}

func (r *teamHandler) changeTeam(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item, changes keybase1.TeamChangeSet) error {
	var rows []keybase1.TeamChangeRow
	r.G().Log.CDebugf(ctx, "teamHandler: changeTeam received")
	if err := json.Unmarshal(item.Body().Bytes(), &rows); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.(change|rename) item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "team.(change|rename) unmarshaled: %+v", rows)
	if err := teams.HandleChangeNotification(ctx, r.G(), rows, changes); err != nil {
		return err
	}

	// Locally dismiss this now that we have processed it so we can avoid replaying it over and over
	if err := r.G().GregorDismisser.LocalDismissItem(ctx, item.Metadata().MsgID()); err != nil {
		r.G().Log.CDebugf(ctx, "failed to local dismiss team change: %s", err)
	}

	// check the badge state to see if any team reset badges need dismissal
	for _, row := range rows {
		badges := r.badger.State().FindResetMemberBadges(row.Name)

		if len(badges) == 0 {
			continue
		}

		// load this team and see if any of the badge users are active members
		details, err := teams.Details(ctx, r.G(), row.Name, false)
		if err != nil {
			r.G().Log.CDebugf(ctx, "error getting team details: %s", err)
			// not fatal
			continue
		}

		activeUsernames := details.Members.ActiveUsernames()

		for _, badge := range badges {
			active, inTeam := activeUsernames[badge.Username]
			if !inTeam {
				// the user is not in the team anymore, so dismiss the
				// gregor message for this badge
				r.G().Log.CDebugf(ctx, "user %s is not in team %s, dismissing TeamMemberOutFromReset badge", badge.Username, row.Name)
				if err := r.G().GregorDismisser.DismissItem(ctx, cli, badge.Id); err != nil {
					r.G().Log.CDebugf(ctx, "failed to dismiss TeamMemberOutFromReset badge: %s", err)
				}
			} else if active {
				// the user is active in the team, so dismiss the gregor message
				// for this badge
				r.G().Log.CDebugf(ctx, "user %s is active in team %s, dismissing TeamMemberOutFromReset badge", badge.Username, row.Name)
				if err := r.G().GregorDismisser.DismissItem(ctx, cli, badge.Id); err != nil {
					r.G().Log.CDebugf(ctx, "failed to dismiss TeamMemberOutFromReset badge: %s", err)
				}
			}
		}
	}

	return nil
}

func (r *teamHandler) deleteTeam(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	var rows []keybase1.TeamChangeRow
	if err := json.Unmarshal(item.Body().Bytes(), &rows); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.(change|rename) item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "teamHandler: team.delete unmarshaled: %+v", rows)

	err := teams.HandleDeleteNotification(ctx, r.G(), rows)
	if err != nil {
		return err
	}

	return r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
}

func (r *teamHandler) exitTeam(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	var rows []keybase1.TeamExitRow
	if err := json.Unmarshal(item.Body().Bytes(), &rows); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.exit item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "teamHandler: team.exit unmarshaled: %+v", rows)
	err := teams.HandleExitNotification(ctx, r.G(), rows)
	if err != nil {
		return err
	}

	r.G().Log.Debug("dismissing team.exit: %v", item.Metadata().MsgID().String())
	return r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
}

func (r *teamHandler) sharingBeforeSignup(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	r.G().Log.CDebugf(ctx, "teamHandler: team.sbs received")
	var msg keybase1.TeamSBSMsg
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.sbs item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "team.sbs unmarshaled: %+v", msg)

	if err := teams.HandleSBSRequest(ctx, r.G(), msg); err != nil {
		return err
	}

	r.G().Log.Debug("dismissing team.sbs item since it succeeded")
	return r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
}

func (r *teamHandler) openTeamAccessRequest(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	r.G().Log.CDebugf(ctx, "teamHandler: team.openreq received")
	var msg keybase1.TeamOpenReqMsg
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.openreq item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "team.openreq unmarshaled: %+v", msg)

	if err := teams.HandleOpenTeamAccessRequest(ctx, r.G(), msg); err != nil {
		return err
	}

	r.G().Log.CDebugf(ctx, "dismissing team.openreq item since it succeeded")
	return r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
}

func (r *teamHandler) seitanCompletion(ctx context.Context, cli gregor1.IncomingInterface, item gregor.Item) error {
	r.G().Log.CDebugf(ctx, "teamHandler: team.seitan received")
	var msg keybase1.TeamSeitanMsg
	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
		r.G().Log.CDebugf(ctx, "error unmarshaling team.seitan item: %s", err)
		return err
	}
	r.G().Log.CDebugf(ctx, "team.seitan unmarshaled: %+v", msg)

	if err := teams.HandleTeamSeitan(ctx, r.G(), msg); err != nil {
		return err
	}

	r.G().Log.CDebugf(ctx, "dismissing team.seitan item since it succeeded")
	return r.G().GregorDismisser.DismissItem(ctx, cli, item.Metadata().MsgID())
}

func (r *teamHandler) Dismiss(ctx context.Context, cli gregor1.IncomingInterface, category string, item gregor.Item) (bool, error) {
	return false, nil
}

func (r *teamHandler) IsAlive() bool {
	return true
}

func (r *teamHandler) Name() string {
	return teamHandlerName
}
<|endoftext|>


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

package tableacl

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"sort"
	"strings"
	"sync"

	log "github.com/golang/glog"
	proto "github.com/golang/protobuf/proto"
	tableaclpb "github.com/youtube/vitess/go/vt/proto/tableacl"
	"github.com/youtube/vitess/go/vt/tableacl/acl"
)

type aclEntry struct {
	tableNameOrPrefix string
	acl               map[Role]acl.ACL
}

type aclEntries []aclEntry

func (aes aclEntries) Len() int {
	return len(aes)
}

func (aes aclEntries) Less(i, j int) bool {
	return aes[i].tableNameOrPrefix < aes[j].tableNameOrPrefix
}

func (aes aclEntries) Swap(i, j int) {
	aes[i], aes[j] = aes[j], aes[i]
}

// mu protects acls and defaultACL.
var mu sync.Mutex

var acls = make(map[string]acl.Factory)

// defaultACL tells the default ACL implementation to use.
var defaultACL string

type tableACL struct {
	sync.RWMutex
	entries aclEntries
}

// currentACL stores current effective ACL information.
var currentACL tableACL

// Init initiates table ACLs.
func Init(configFile string) {
	data, err := ioutil.ReadFile(configFile)
	if err != nil {
		log.Errorf("unable to read tableACL config file: %v", err)
		panic(fmt.Errorf("unable to read tableACL config file: %v", err))
	}
	config := &tableaclpb.Config{}
	if err := proto.Unmarshal(data, config); err != nil {
		log.Errorf("unable to parse tableACL config file as a protobuf file: %v", err)
		// try to parse tableacl as json file
		if jsonErr := json.Unmarshal(data, config); jsonErr != nil {
			log.Errorf("unable to parse tableACL config file as a json file: %v", jsonErr)
			panic(fmt.Errorf("unable to parse tableACL config file: %v", err))
		}
	}
	if err = load(config); err != nil {
		log.Errorf("tableACL initialization error: %v", err)
		panic(fmt.Errorf("tableACL initialization error: %v", err))
	}
}

// InitFromProto inits table ACLs from a proto.
func InitFromProto(config *tableaclpb.Config) (err error) {
	return load(config)
}

// load loads configurations from a JSON byte array
//
// Sample configuration
// []byte (`{
//	<table name or table name prefix>: {"READER": "*", "WRITER": "<u2>,<u4>...","ADMIN": "<u5>"},
//	<table name or table name prefix>: {"ADMIN": "<u5>"}
//}`)
func load(config *tableaclpb.Config) error {
	var entries aclEntries
	for _, group := range config.TableGroups {
		readers, err := newACL(group.Readers)
		if err != nil {
			return err
		}
		writers, err := newACL(group.Writers)
		if err != nil {
			return err
		}
		admins, err := newACL(group.Admins)
		if err != nil {
			return err
		}
		for _, tableNameOrPrefix := range group.TableNamesOrPrefixes {
			entries = append(entries, aclEntry{
				tableNameOrPrefix: tableNameOrPrefix,
				acl: map[Role]acl.ACL{
					READER: readers,
					WRITER: writers,
					ADMIN:  admins,
				},
			})
		}
	}
	sort.Sort(entries)
	if err := validate(entries); err != nil {
		return err
	}
	currentACL.Lock()
	defer currentACL.Unlock()
	currentACL.entries = entries
	return nil
}

func validate(entries aclEntries) error {
	// TODO: shengzhe add acl entries validation logic
	return nil
}

// Authorized returns the list of entities who have the specified role on a tablel.
func Authorized(table string, role Role) acl.ACL {
	currentACL.RLock()
	defer currentACL.RUnlock()
	start := 0
	end := len(currentACL.entries)
	for start < end {
		mid := start + (end-start)/2
		val := currentACL.entries[mid].tableNameOrPrefix
		if table == val || (strings.HasSuffix(val, "%") && strings.HasPrefix(table, val[:len(val)-1])) {
			acl, ok := currentACL.entries[mid].acl[role]
			if ok {
				return acl
			}
			break
		} else if table < val {
			end = mid
		} else {
			start = mid + 1
		}
	}
	return acl.AcceptAllACL{}
}

// Register registers a AclFactory.
func Register(name string, factory acl.Factory) {
	mu.Lock()
	defer mu.Unlock()
	if _, ok := acls[name]; ok {
		panic(fmt.Sprintf("register a registered key: %s", name))
	}
	acls[name] = factory
}

// SetDefaultACL sets the default ACL implementation.
func SetDefaultACL(name string) {
	mu.Lock()
	defer mu.Unlock()
	defaultACL = name
}

// GetCurrentAclFactory returns current table acl implementation.
func GetCurrentAclFactory() acl.Factory {
	mu.Lock()
	defer mu.Unlock()
	if defaultACL == "" {
		if len(acls) == 1 {
			for _, aclFactory := range acls {
				return aclFactory
			}
		}
		panic("there are more than one AclFactory " +
			"registered but no default has been given.")
	}
	aclFactory, ok := acls[defaultACL]
	if !ok {
		panic(fmt.Sprintf("aclFactory for given default: %s is not found.", defaultACL))
	}
	return aclFactory
}

func newACL(entries []string) (acl.ACL, error) {
	return GetCurrentAclFactory().New(entries)
}
<commit_msg>add GetCurrentConfig func in tableacl<commit_after>// Copyright 2015, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tableacl

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"sort"
	"strings"
	"sync"

	log "github.com/golang/glog"
	proto "github.com/golang/protobuf/proto"
	tableaclpb "github.com/youtube/vitess/go/vt/proto/tableacl"
	"github.com/youtube/vitess/go/vt/tableacl/acl"
)

type aclEntry struct {
	tableNameOrPrefix string
	acl               map[Role]acl.ACL
}

type aclEntries []aclEntry

func (aes aclEntries) Len() int {
	return len(aes)
}

func (aes aclEntries) Less(i, j int) bool {
	return aes[i].tableNameOrPrefix < aes[j].tableNameOrPrefix
}

func (aes aclEntries) Swap(i, j int) {
	aes[i], aes[j] = aes[j], aes[i]
}

// mu protects acls and defaultACL.
var mu sync.Mutex

var acls = make(map[string]acl.Factory)

// defaultACL tells the default ACL implementation to use.
var defaultACL string

type tableACL struct {
	sync.RWMutex
	entries aclEntries
	config  tableaclpb.Config
}

// currentACL stores current effective ACL information.
var currentACL tableACL

// Init initiates table ACLs.
func Init(configFile string) {
	data, err := ioutil.ReadFile(configFile)
	if err != nil {
		log.Errorf("unable to read tableACL config file: %v", err)
		panic(fmt.Errorf("unable to read tableACL config file: %v", err))
	}
	config := &tableaclpb.Config{}
	if err := proto.Unmarshal(data, config); err != nil {
		log.Errorf("unable to parse tableACL config file as a protobuf file: %v", err)
		// try to parse tableacl as json file
		if jsonErr := json.Unmarshal(data, config); jsonErr != nil {
			log.Errorf("unable to parse tableACL config file as a json file: %v", jsonErr)
			panic(fmt.Errorf("unable to parse tableACL config file: %v", err))
		}
	}
	if err = load(config); err != nil {
		log.Errorf("tableACL initialization error: %v", err)
		panic(fmt.Errorf("tableACL initialization error: %v", err))
	}
}

// InitFromProto inits table ACLs from a proto.
func InitFromProto(config *tableaclpb.Config) (err error) {
	return load(config)
}

// load loads configurations from a JSON byte array
//
// Sample configuration
// []byte (`{
//	<table name or table name prefix>: {"READER": "*", "WRITER": "<u2>,<u4>...","ADMIN": "<u5>"},
//	<table name or table name prefix>: {"ADMIN": "<u5>"}
//}`)
func load(config *tableaclpb.Config) error {
	var entries aclEntries
	for _, group := range config.TableGroups {
		readers, err := newACL(group.Readers)
		if err != nil {
			return err
		}
		writers, err := newACL(group.Writers)
		if err != nil {
			return err
		}
		admins, err := newACL(group.Admins)
		if err != nil {
			return err
		}
		for _, tableNameOrPrefix := range group.TableNamesOrPrefixes {
			entries = append(entries, aclEntry{
				tableNameOrPrefix: tableNameOrPrefix,
				acl: map[Role]acl.ACL{
					READER: readers,
					WRITER: writers,
					ADMIN:  admins,
				},
			})
		}
	}
	sort.Sort(entries)
	if err := validate(entries); err != nil {
		return err
	}
	currentACL.Lock()
	defer currentACL.Unlock()
	currentACL.entries = entries
	currentACL.config = *config
	return nil
}

func validate(entries aclEntries) error {
	// TODO: shengzhe add acl entries validation logic
	return nil
}

// Authorized returns the list of entities who have the specified role on a tablel.
func Authorized(table string, role Role) acl.ACL {
	currentACL.RLock()
	defer currentACL.RUnlock()
	start := 0
	end := len(currentACL.entries)
	for start < end {
		mid := start + (end-start)/2
		val := currentACL.entries[mid].tableNameOrPrefix
		if table == val || (strings.HasSuffix(val, "%") && strings.HasPrefix(table, val[:len(val)-1])) {
			acl, ok := currentACL.entries[mid].acl[role]
			if ok {
				return acl
			}
			break
		} else if table < val {
			end = mid
		} else {
			start = mid + 1
		}
	}
	return acl.AcceptAllACL{}
}

// GetCurrentConfig returns a copy of current tableacl configuration.
func GetCurrentConfig() *tableaclpb.Config {
	config := &tableaclpb.Config{}
	currentACL.RLock()
	defer currentACL.RUnlock()
	*config = currentACL.config
	return config
}

// Register registers a AclFactory.
func Register(name string, factory acl.Factory) {
	mu.Lock()
	defer mu.Unlock()
	if _, ok := acls[name]; ok {
		panic(fmt.Sprintf("register a registered key: %s", name))
	}
	acls[name] = factory
}

// SetDefaultACL sets the default ACL implementation.
func SetDefaultACL(name string) {
	mu.Lock()
	defer mu.Unlock()
	defaultACL = name
}

// GetCurrentAclFactory returns current table acl implementation.
func GetCurrentAclFactory() acl.Factory {
	mu.Lock()
	defer mu.Unlock()
	if defaultACL == "" {
		if len(acls) == 1 {
			for _, aclFactory := range acls {
				return aclFactory
			}
		}
		panic("there are more than one AclFactory " +
			"registered but no default has been given.")
	}
	aclFactory, ok := acls[defaultACL]
	if !ok {
		panic(fmt.Sprintf("aclFactory for given default: %s is not found.", defaultACL))
	}
	return aclFactory
}

func newACL(entries []string) (acl.ACL, error) {
	return GetCurrentAclFactory().New(entries)
}
<|endoftext|>


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

package vcmp

import "github.com/e-XpertSolutions/f5-rest-client/f5"

// GuestList holds a list of Guests.
type GuestList struct {
	Items    []Guest `json:"items,omitempty"`
	Kind     string  `json:"kind,omitempty"`
	SelfLink string  `json:"selflink,omitempty"`
}

// Guest holds the configuration of a single Guest.
type Guest struct {
	Name              string   `json:"name,omitempty"`
	AllowedSlots      []int    `json:"allowedSlots,omitempty"`
	AssignedSlots     []int    `json:"assignedSlots,omitempty"`
	AppService        string   `json:"appService,omitempty"`
	CoresPerSlot      int      `json:"coresPerSlot,omitempty"`
	Hostname          string   `json:"hostname,omitempty"`
	InitialHotfix     string   `json:"initialHotfix,omitempty"`
	InitialImage      string   `json:"initialImage,omitempty"`
	ManagementGW      string   `json:"managementGw,omitempty"`
	ManagementIP      string   `json:"managementIp,omitempty"`
	ManagementNetwork string   `json:"managementNetwork,omitempty"`
	MinSlots          int      `json:"minSlots,omitempty"`
	PreferredSLots    int      `json:"preferredSlots,omitempty"`
	Slots             int      `json:"slots,omitempty"`
	SSLMode           string   `json:"sslMode,omitempty"`
	State             string   `json:"state,omitempty"`
	SymUnitKey        string   `json:"symUnitKey,omitempty"`
	TrafficProfile    string   `json:"trafficProfile,omitempty"`
	VirtualDisk       string   `json:"virtualDisk,omitempty"`
	VLAN              []string `json:"vlans,omitempty"`
	VLANRef           []struct {
		Link string `json:"link,omitempty"`
	} `json:"vlansReference,omitempty"`
}

// GuestEndpoint represents the REST resource for managing Guest.
const GuestEndpoint = "/guest"

// GuestResource provides an API to manage Guest configurations.
type GuestResource struct {
	c *f5.Client
}

// ListAll  lists all the Guest configurations.
func (r *GuestResource) ListAll() (*GuestList, error) {
	var list GuestList
	if err := r.c.ReadQuery(BasePath+GuestEndpoint, &list); err != nil {
		return nil, err
	}
	return &list, nil
}

// Get a single Guest configuration identified by id.
func (r *GuestResource) Get(id string) (*Guest, error) {
	var item Guest
	if err := r.c.ReadQuery(BasePath+GuestEndpoint, &item); err != nil {
		return nil, err
	}
	return &item, nil
}

// Create a new Guest configuration.
func (r *GuestResource) Create(item Guest) error {
	if err := r.c.ModQuery("POST", BasePath+GuestEndpoint, item); err != nil {
		return err
	}
	return nil
}

// Edit a Guest configuration identified by id.
func (r *GuestResource) Edit(id string, item Guest) error {
	if err := r.c.ModQuery("PUT", BasePath+GuestEndpoint+"/"+id, item); err != nil {
		return err
	}
	return nil
}

// Delete a single Guest configuration identified by id.
func (r *GuestResource) Delete(id string) error {
	if err := r.c.ModQuery("DELETE", BasePath+GuestEndpoint+"/"+id, nil); err != nil {
		return err
	}
	return nil
}
<commit_msg>f5/vcmp: add a method to change the state of a guest<commit_after>// Copyright e-Xpert Solutions SA. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vcmp

import (
	"fmt"

	"github.com/e-XpertSolutions/f5-rest-client/f5"
)

// GuestList holds a list of Guests.
type GuestList struct {
	Items    []Guest `json:"items,omitempty"`
	Kind     string  `json:"kind,omitempty"`
	SelfLink string  `json:"selflink,omitempty"`
}

// Guest holds the configuration of a single Guest.
type Guest struct {
	Name              string   `json:"name,omitempty"`
	AllowedSlots      []int    `json:"allowedSlots,omitempty"`
	AssignedSlots     []int    `json:"assignedSlots,omitempty"`
	AppService        string   `json:"appService,omitempty"`
	CoresPerSlot      int      `json:"coresPerSlot,omitempty"`
	Hostname          string   `json:"hostname,omitempty"`
	InitialHotfix     string   `json:"initialHotfix,omitempty"`
	InitialImage      string   `json:"initialImage,omitempty"`
	ManagementGW      string   `json:"managementGw,omitempty"`
	ManagementIP      string   `json:"managementIp,omitempty"`
	ManagementNetwork string   `json:"managementNetwork,omitempty"`
	MinSlots          int      `json:"minSlots,omitempty"`
	PreferredSLots    int      `json:"preferredSlots,omitempty"`
	Slots             int      `json:"slots,omitempty"`
	SSLMode           string   `json:"sslMode,omitempty"`
	State             string   `json:"state,omitempty"`
	SymUnitKey        string   `json:"symUnitKey,omitempty"`
	TrafficProfile    string   `json:"trafficProfile,omitempty"`
	VirtualDisk       string   `json:"virtualDisk,omitempty"`
	VLAN              []string `json:"vlans,omitempty"`
	VLANRef           []struct {
		Link string `json:"link,omitempty"`
	} `json:"vlansReference,omitempty"`
}

// GuestEndpoint represents the REST resource for managing Guest.
const GuestEndpoint = "/guest"

// GuestResource provides an API to manage Guest configurations.
type GuestResource struct {
	c *f5.Client
}

// ListAll  lists all the Guest configurations.
func (r *GuestResource) ListAll() (*GuestList, error) {
	var list GuestList
	if err := r.c.ReadQuery(BasePath+GuestEndpoint, &list); err != nil {
		return nil, err
	}
	return &list, nil
}

// Get a single Guest configuration identified by id.
func (r *GuestResource) Get(id string) (*Guest, error) {
	var item Guest
	if err := r.c.ReadQuery(BasePath+GuestEndpoint, &item); err != nil {
		return nil, err
	}
	return &item, nil
}

// Create a new Guest configuration.
func (r *GuestResource) Create(item Guest) error {
	if err := r.c.ModQuery("POST", BasePath+GuestEndpoint, item); err != nil {
		return err
	}
	return nil
}

// Edit a Guest configuration identified by id.
func (r *GuestResource) Edit(id string, item Guest) error {
	if err := r.c.ModQuery("PUT", BasePath+GuestEndpoint+"/"+id, item); err != nil {
		return err
	}
	return nil
}

// Delete a single Guest configuration identified by id.
func (r *GuestResource) Delete(id string) error {
	if err := r.c.ModQuery("DELETE", BasePath+GuestEndpoint+"/"+id, nil); err != nil {
		return err
	}
	return nil
}

// ChangeState changes the state of a Guest.
func (r *GuestResource) ChangeState(id, state string) error {
	if state != "deployed" && state != "provisioned" && state != "configured" {
		return fmt.Errorf("invalid state value %q", state)
	}
	data := map[string]interface{}{
		"state": state,
	}
	if err := r.c.ModQuery("PATCH", BasePath+GuestEndpoint+"/"+id, data); err != nil {
		return err
	}
	return nil
}
<|endoftext|>