<commit_before>package main

import (
	"fmt"
	"github.com/fzzy/radix/redis"
	"math/rand"
	"os"
	"os/exec"
	"regexp"
	"strings"
)

var cmdDb *redis.Client

//used for calling functions using string variable contents
type command func(chan string, string, string, string, []string)

func initMap() map[string]command {
	return map[string]command{
		"source":   command(source),
		"botsnack": command(botsnack),
		"register": command(register),
		"uptime":   command(uptime),
		"web":      command(web),
		"login":    command(login),
		"verify":   command(verify),
		"verified": command(verified),
		"help":     command(help),
		"commands": command(commands),
		"kick":     command(kick),
		"wc":       command(wc),
		"top5":     command(top5),
	}
}

func initCmdRedis() {
	var err error
	cmdDb, err = redis.Dial("tcp", "127.0.0.1:6379")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func source(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://github.com/heydabop/yaircb"
	fmt.Println(message)
	srvChan <- message
}

func botsnack(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :Kisses commend. Perplexities deprave."
	fmt.Println(message)
	srvChan <- message
}

func register(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/register/"
	fmt.Println(message)
	srvChan <- message
}

func uptime(srvChan chan string, channel, nick, hostname string, args []string) {
	out, err := exec.Command("uptime").Output()
	message := "PRIVMSG " + channel + " :" + strings.TrimSpace(string(out))
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(message)
	srvChan <- message
}

func web(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/"
	fmt.Println(message)
	srvChan <- message
}

func login(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/login/"
	fmt.Println(message)
	srvChan <- message
}

func verify(srvChan chan string, channel, nick, hostname string, args []string) {
	var message string
	if len(args) != 2 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		uname := args[0]
		pin := args[1]
		reply := cmdDb.Cmd("get", uname+"Pin")
		pinDb, err := (reply.Bytes())
		if err != nil {
			message = "PRIVMSG " + channel + " :" + fmt.Sprintf("%s", err)
		} else {
			if string(pinDb) == pin {
				message = "PRIVMSG " + channel + " :You are now verified as " + uname
				cmdDb.Cmd("set", uname+"Host", hostname)
				cmdDb.Cmd("set", uname+"Pin", fmt.Sprintf("%06d", rand.Intn(1000000)))
			} else {
				message = "PRIVMSG " + channel + " :PIN does not match that of " + uname
			}
		}
	}
	fmt.Println(message)
	srvChan <- message
}

func verified(srvChan chan string, channel, nick, hostname string, args []string) {
	var message string
	if len(args) != 1 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		uname := args[0]
		reply := cmdDb.Cmd("get", uname+"Host")
		hostnameDb, err := reply.Bytes()
		if err != nil {
			message = "PRIVMSG " + channel + " :" + fmt.Sprintf("%s", err)
		} else {
			if hostname == string(hostnameDb) {
				message = "PRIVMSG " + channel + " :You are " + uname + " at " + hostname
			} else {
				message = "PRIVMSG " + channel + " :You are not " + uname
			}
		}
	}
	fmt.Println(message)
	srvChan <- message
}

func help(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :8)"
	fmt.Println(message)
	srvChan <- message
}

func commands(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :"
	for command := range funcMap {
		message += command + " "
	}
	fmt.Println(message)
	srvChan <- message
}

func kick(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "KICK " + channel + " " + nick + " :You don't tell me what to do."
	fmt.Println(message)
	srvChan <- message

	message = "KICK " + channel
	if len(args) < 1 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		if args[0] == config.Nick {
			return
		}
		message += " " + args[0]
	}
	if len(args) >= 2 {
		message += " :" + strings.Join(args[1:], " ")
	}
	fmt.Println(message)
	srvChan <- message
}

func wc(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :"
	if len(args) != 1 {
		message += "ERROR: Invalid number of arguments"
	} else {
		logFile, err := os.Open(`/home/ross/irclogs/freenode/` + channel + `.log`)
		if err != nil {
			message += fmt.Sprintf("%s", err)
		} else {
			fileStat, err := logFile.Stat()
			if err != nil {
				message += fmt.Sprintf("%s", err)
			} else {
				log := make([]byte, fileStat.Size())
				_, err = logFile.Read(log)
				if err != nil {
					message += fmt.Sprintf("%s", err)
				} else {
					logLines := strings.Split(string(log),"\n")
					nickLine := regexp.MustCompile(`^\d\d:\d\d <[@\+\s]?` + args[0] + `>`)
					matches := 0
					for _, line := range logLines {
						if match := nickLine.FindStringSubmatch(line); match != nil {
							matches++
						}
					}
					message += args[0] + ": " + fmt.Sprintf("%d", matches) + " lines"
				}
			}
		}
	}
	fmt.Println(message)
	srvChan <- message
}

func top5(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :"
	logFile, err := os.Open(`/home/ross/irclogs/freenode/` + channel + `.log`)
	if err != nil {
		message += fmt.Sprintf("%s", err)
	} else {
		fileStat, err := logFile.Stat()
		if err != nil {
			message += fmt.Sprintf("%s", err)
		} else {
			log := make([]byte, fileStat.Size())
			_, err = logFile.Read(log)
			if err != nil {
				message += fmt.Sprintf("%s", err)
			} else {
				logLines := strings.Split(string(log),"\n")
				nickLine := regexp.MustCompile(`^\d\d:\d\d <[@\+\s]?(\S*?)>`)
				matches := make(map[string]uint)
				for _, line := range logLines {
					if match := nickLine.FindStringSubmatch(line); match != nil {
						matches[strings.ToLower(match[1])]++
					}
				}
				for i := 0; i < 5; i++ {
					maxLines := uint(0)
					var maxNick string
					for nick, lines := range matches {
						if lines > maxLines {
							maxLines = lines
							maxNick = nick
						}
					}
					if maxLines < 1 {
						break
					}
					message += string(maxNick[0]) + string('\u200B') + maxNick[1:] + ": " + fmt.Sprintf("%d", maxLines) + " lines || "
					delete(matches, maxNick)
				}
			}
		}
	}
	fmt.Println(message)
	srvChan <- message
}
<commit_msg>changed top5 to top #, where # is arg of nicks to check<commit_after>package main

import (
	"fmt"
	"github.com/fzzy/radix/redis"
	"math/rand"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"strconv"
)

var cmdDb *redis.Client

//used for calling functions using string variable contents
type command func(chan string, string, string, string, []string)

func initMap() map[string]command {
	return map[string]command{
		"source":   command(source),
		"botsnack": command(botsnack),
		"register": command(register),
		"uptime":   command(uptime),
		"web":      command(web),
		"login":    command(login),
		"verify":   command(verify),
		"verified": command(verified),
		"help":     command(help),
		"commands": command(commands),
		"kick":     command(kick),
		"wc":       command(wc),
		"top":     command(top),
	}
}

func initCmdRedis() {
	var err error
	cmdDb, err = redis.Dial("tcp", "127.0.0.1:6379")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func source(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://github.com/heydabop/yaircb"
	fmt.Println(message)
	srvChan <- message
}

func botsnack(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :Kisses commend. Perplexities deprave."
	fmt.Println(message)
	srvChan <- message
}

func register(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/register/"
	fmt.Println(message)
	srvChan <- message
}

func uptime(srvChan chan string, channel, nick, hostname string, args []string) {
	out, err := exec.Command("uptime").Output()
	message := "PRIVMSG " + channel + " :" + strings.TrimSpace(string(out))
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(message)
	srvChan <- message
}

func web(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/"
	fmt.Println(message)
	srvChan <- message
}

func login(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/login/"
	fmt.Println(message)
	srvChan <- message
}

func verify(srvChan chan string, channel, nick, hostname string, args []string) {
	var message string
	if len(args) != 2 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		uname := args[0]
		pin := args[1]
		reply := cmdDb.Cmd("get", uname+"Pin")
		pinDb, err := (reply.Bytes())
		if err != nil {
			message = "PRIVMSG " + channel + " :" + fmt.Sprintf("%s", err)
		} else {
			if string(pinDb) == pin {
				message = "PRIVMSG " + channel + " :You are now verified as " + uname
				cmdDb.Cmd("set", uname+"Host", hostname)
				cmdDb.Cmd("set", uname+"Pin", fmt.Sprintf("%06d", rand.Intn(1000000)))
			} else {
				message = "PRIVMSG " + channel + " :PIN does not match that of " + uname
			}
		}
	}
	fmt.Println(message)
	srvChan <- message
}

func verified(srvChan chan string, channel, nick, hostname string, args []string) {
	var message string
	if len(args) != 1 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		uname := args[0]
		reply := cmdDb.Cmd("get", uname+"Host")
		hostnameDb, err := reply.Bytes()
		if err != nil {
			message = "PRIVMSG " + channel + " :" + fmt.Sprintf("%s", err)
		} else {
			if hostname == string(hostnameDb) {
				message = "PRIVMSG " + channel + " :You are " + uname + " at " + hostname
			} else {
				message = "PRIVMSG " + channel + " :You are not " + uname
			}
		}
	}
	fmt.Println(message)
	srvChan <- message
}

func help(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :8)"
	fmt.Println(message)
	srvChan <- message
}

func commands(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :"
	for command := range funcMap {
		message += command + " "
	}
	fmt.Println(message)
	srvChan <- message
}

func kick(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "KICK " + channel + " " + nick + " :You don't tell me what to do."
	fmt.Println(message)
	srvChan <- message

	message = "KICK " + channel
	if len(args) < 1 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		if args[0] == config.Nick {
			return
		}
		message += " " + args[0]
	}
	if len(args) >= 2 {
		message += " :" + strings.Join(args[1:], " ")
	}
	fmt.Println(message)
	srvChan <- message
}

func wc(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :"
	if len(args) != 1 {
		message += "ERROR: Invalid number of arguments"
	} else {
		logFile, err := os.Open(`/home/ross/irclogs/freenode/` + channel + `.log`)
		if err != nil {
			message += fmt.Sprintf("%s", err)
		} else {
			fileStat, err := logFile.Stat()
			if err != nil {
				message += fmt.Sprintf("%s", err)
			} else {
				log := make([]byte, fileStat.Size())
				_, err = logFile.Read(log)
				if err != nil {
					message += fmt.Sprintf("%s", err)
				} else {
					logLines := strings.Split(string(log),"\n")
					nickLine := regexp.MustCompile(`^\d\d:\d\d <[@\+\s]?` + args[0] + `>`)
					matches := 0
					for _, line := range logLines {
						if match := nickLine.FindStringSubmatch(line); match != nil {
							matches++
						}
					}
					message += args[0] + ": " + fmt.Sprintf("%d", matches) + " lines"
				}
			}
		}
	}
	fmt.Println(message)
	srvChan <- message
}

func top(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :"
	if len(args) != 1 {
		message += "ERROR: Invalid number of arguments"
	} else {
		nicks64, err := strconv.ParseInt(args[0], 10, 0)
		if err != nil {
			message += fmt.Sprintf("%s", err)
		} else {
			nicks := int(nicks64)
			logFile, err := os.Open(`/home/ross/irclogs/freenode/` + channel + `.log`)
			if err != nil {
				message += fmt.Sprintf("%s", err)
			} else {
				fileStat, err := logFile.Stat()
				if err != nil {
					message += fmt.Sprintf("%s", err)
				} else {
					log := make([]byte, fileStat.Size())
					_, err = logFile.Read(log)
					if err != nil {
						message += fmt.Sprintf("%s", err)
					} else {
						logLines := strings.Split(string(log),"\n")
						nickLine := regexp.MustCompile(`^\d\d:\d\d <[@\+\s]?(\S*?)>`)
						matches := make(map[string]uint)
						for _, line := range logLines {
							if match := nickLine.FindStringSubmatch(line); match != nil {
								matches[strings.ToLower(match[1])]++
							}
						}
						for i := 0; i < nicks; i++ {
							maxLines := uint(0)
							var maxNick string
							for nick, lines := range matches {
								if lines > maxLines {
									maxLines = lines
									maxNick = nick
								}
							}
							if maxLines < 1 {
								break
							}
							message += string(maxNick[0]) + string('\u200B') + maxNick[1:] + ": " + fmt.Sprintf("%d", maxLines) + " lines || "
							delete(matches, maxNick)
						}
					}
				}
			}
		}
	}
	fmt.Println(message)
	srvChan <- message
}
<|endoftext|>


<commit_before>/*
 * Spreed Speak Freely.
 * Copyright (C) 2013-2014 struktur AG
 *
 * This file is part of Spreed Speak Freely.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/gorilla/securecookie"
	"log"
	"sync"
	"sync/atomic"
	"time"
)

const (
	turnTTL               = 3600 // XXX(longsleep): Add to config file.
	maxBroadcastPerSecond = 1000
	maxUsersLength        = 5000
)

type MessageRequest struct {
	From    string
	To      string
	Message Buffer
	Id      string
}

type HubStat struct {
	Rooms                 int                  `json:"rooms"`
	Connections           int                  `json:"connections"`
	Users                 int                  `json:"users"`
	Count                 uint64               `json:"count"`
	BroadcastChatMessages uint64               `json:"broadcastchatmessages"`
	UnicastChatMessages   uint64               `json:"unicastchatmessages"`
	IdsInRoom             map[string][]string  `json:"idsinroom,omitempty"`
	UsersById             map[string]*DataUser `json:"usersbyid,omitempty"`
	ConnectionsByIdx      map[string]string    `json:"connectionsbyidx,omitempty"`
}

type Hub struct {
	server                *Server
	connectionTable       map[string]*Connection
	userTable             map[string]*User
	roomTable             map[string]*RoomWorker
	version               string
	config                *Config
	sessionSecret         []byte
	turnSecret            []byte
	turnUsernameFormat    string
	tickets               *securecookie.SecureCookie
	count                 uint64
	mutex                 sync.RWMutex
	buffers               BufferCache
	broadcastChatMessages uint64
	unicastChatMessages   uint64
}

func NewHub(version string, config *Config, sessionSecret, turnSecret, turnUsernameFormat string) *Hub {

	h := &Hub{
		connectionTable:    make(map[string]*Connection),
		userTable:          make(map[string]*User),
		roomTable:          make(map[string]*RoomWorker),
		version:            version,
		config:             config,
		sessionSecret:      []byte(sessionSecret),
		turnSecret:         []byte(turnSecret),
		turnUsernameFormat: turnUsernameFormat,
	}

	h.tickets = securecookie.New(h.sessionSecret, nil)
	h.buffers = NewBufferCache(1024, bytes.MinRead)
	return h

}

func (h *Hub) Stat(details bool) *HubStat {
	h.mutex.RLock()
	defer h.mutex.RUnlock()
	stat := &HubStat{
		Rooms:       len(h.roomTable),
		Connections: len(h.connectionTable),
		Users:       len(h.userTable),
		Count:       h.count,
		BroadcastChatMessages: atomic.LoadUint64(&h.broadcastChatMessages),
		UnicastChatMessages:   atomic.LoadUint64(&h.unicastChatMessages),
	}
	if details {
		rooms := make(map[string][]string)
		for roomid, room := range h.roomTable {
			users := make([]string, 0, len(room.connections))
			for id, _ := range room.connections {
				users = append(users, id)
			}
			rooms[roomid] = users
		}
		stat.IdsInRoom = rooms
		users := make(map[string]*DataUser)
		for userid, user := range h.userTable {
			users[userid] = user.Data()
		}
		stat.UsersById = users
		connections := make(map[string]string)
		for id, connection := range h.connectionTable {
			connections[fmt.Sprintf("%d", connection.Idx)] = id
		}
		stat.ConnectionsByIdx = connections
	}
	return stat
}

func (h *Hub) CreateTurnData(id string) *DataTurn {

	// Create turn data credentials for shared secret auth with TURN
	// server. See http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00
	// and https://code.google.com/p/rfc5766-turn-server/ REST API auth
	// and set shared secret in TURN server with static-auth-secret.
	if len(h.turnSecret) == 0 {
		return &DataTurn{}
	}
	var user string
	bar := sha256.New()
	bar.Write([]byte(id))
	id = base64.StdEncoding.EncodeToString(bar.Sum(nil))
	foo := hmac.New(sha1.New, h.turnSecret)
	now := int32(time.Now().Unix())
	switch h.turnUsernameFormat {
	case "time:id":
		user = fmt.Sprintf("%d:%s", now, id)
	default:
		user = fmt.Sprintf("%s:%d", id, now)
	}
	foo.Write([]byte(user))
	password := base64.StdEncoding.EncodeToString(foo.Sum(nil))
	return &DataTurn{user, password, turnTTL, h.config.TurnURIs}

}

func (h *Hub) EncodeTicket(key, value string) (string, error) {

	if value == "" {
		// Create new id.
		value = fmt.Sprintf("%s", securecookie.GenerateRandomKey(16))
	}
	return h.tickets.Encode(key, value)

}

func (h *Hub) DecodeTicket(key, value string) (string, error) {

	result := ""
	err := h.tickets.Decode(key, value, &result)
	return result, err

}

func (h *Hub) GetRoom(id string) *RoomWorker {

	h.mutex.RLock()
	room, ok := h.roomTable[id]
	if !ok {
		h.mutex.RUnlock()
		h.mutex.Lock()
		// need to re-check, another thread might have created the room
		// while we waited for the lock
		room, ok = h.roomTable[id]
		if !ok {
			room = NewRoomWorker(h, id)
			h.roomTable[id] = room
			h.mutex.Unlock()
			go func() {
				// Start room, this blocks until room expired.
				room.Start()
				// Cleanup room when we are done.
				h.mutex.Lock()
				defer h.mutex.Unlock()
				delete(h.roomTable, id)
				log.Printf("Cleaned up room '%s'\n", id)
			}()
		} else {
			h.mutex.Unlock()
		}
	} else {
		h.mutex.RUnlock()
	}

	return room

}

func (h *Hub) GetGlobalConnections() []*Connection {

	if h.config.globalRoomid == "" {
		return make([]*Connection, 0)
	}
	h.mutex.RLock()
	if room, ok := h.roomTable[h.config.globalRoomid]; ok {
		h.mutex.RUnlock()
		return room.GetConnections()
	} else {
		h.mutex.RUnlock()
	}
	return make([]*Connection, 0)

}

func (h *Hub) RunForAllRooms(f func(room *RoomWorker)) {

	h.mutex.RLock()
	for _, room := range h.roomTable {
		f(room)
	}
	h.mutex.RUnlock()

}

func (h *Hub) isGlobalRoomid(id string) bool {

	return id != "" && (id == h.config.globalRoomid)

}

func (h *Hub) isDefaultRoomid(id string) bool {

	return id == ""
}

func (h *Hub) registerHandler(c *Connection) {

	h.mutex.Lock()

	// Create new user instance.
	h.count++
	c.Idx = h.count
	u := &User{Id: c.Id}
	h.userTable[c.Id] = u
	c.User = u
	c.IsRegistered = true

	// Register connection or replace existing one.
	if ec, ok := h.connectionTable[c.Id]; ok {
		delete(h.connectionTable, ec.Id)
		ec.IsRegistered = false
		ec.close()
		h.connectionTable[c.Id] = c
		h.mutex.Unlock()
		//log.Printf("Register (%d) from %s: %s (existing)\n", c.Idx, c.RemoteAddr, c.Id)
	} else {
		h.connectionTable[c.Id] = c
		//fmt.Println("registered", c.Id)
		h.mutex.Unlock()
		//log.Printf("Register (%d) from %s: %s\n", c.Idx, c.RemoteAddr, c.Id)
		h.server.OnRegister(c)
	}

}

func (h *Hub) unregisterHandler(c *Connection) {

	h.mutex.Lock()
	if !c.IsRegistered {
		h.mutex.Unlock()
		return
	}
	c.close()
	delete(h.connectionTable, c.Id)
	delete(h.userTable, c.Id)
	h.mutex.Unlock()
	//log.Printf("Unregister (%d) from %s: %s\n", c.Idx, c.RemoteAddr, c.Id)
	h.server.OnUnregister(c)

}

func (h *Hub) unicastHandler(m *MessageRequest) {

	h.mutex.RLock()
	out, ok := h.connectionTable[m.To]
	h.mutex.RUnlock()
	if !ok {
		log.Println("Unicast To not found", m.To)
		return
	}
	out.send(m.Message)

}

func (h *Hub) aliveHandler(c *Connection, alive *DataAlive) {

	aliveJson := h.buffers.New()
	encoder := json.NewEncoder(aliveJson)
	err := encoder.Encode(&DataOutgoing{From: c.Id, Data: alive})
	if err != nil {
		log.Println("Alive error while encoding JSON", err)
		aliveJson.Decref()
		return
	}
	c.send(aliveJson)
	aliveJson.Decref()

}

func (h *Hub) userupdateHandler(u *UserUpdate) uint64 {

	//fmt.Println("Userupdate", u)
	h.mutex.RLock()
	user, ok := h.userTable[u.Id]
	h.mutex.RUnlock()
	var rev uint64
	if ok {
		rev = user.Update(u)
	} else {
		log.Printf("Update data for unknown user %s\n", u.Id)
	}
	return rev

}
<commit_msg>Use expiration time stamp for TURN REST API auth.<commit_after>/*
 * Spreed Speak Freely.
 * Copyright (C) 2013-2014 struktur AG
 *
 * This file is part of Spreed Speak Freely.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/gorilla/securecookie"
	"log"
	"sync"
	"sync/atomic"
	"time"
)

const (
	turnTTL               = 3600 // XXX(longsleep): Add to config file.
	maxBroadcastPerSecond = 1000
	maxUsersLength        = 5000
)

type MessageRequest struct {
	From    string
	To      string
	Message Buffer
	Id      string
}

type HubStat struct {
	Rooms                 int                  `json:"rooms"`
	Connections           int                  `json:"connections"`
	Users                 int                  `json:"users"`
	Count                 uint64               `json:"count"`
	BroadcastChatMessages uint64               `json:"broadcastchatmessages"`
	UnicastChatMessages   uint64               `json:"unicastchatmessages"`
	IdsInRoom             map[string][]string  `json:"idsinroom,omitempty"`
	UsersById             map[string]*DataUser `json:"usersbyid,omitempty"`
	ConnectionsByIdx      map[string]string    `json:"connectionsbyidx,omitempty"`
}

type Hub struct {
	server                *Server
	connectionTable       map[string]*Connection
	userTable             map[string]*User
	roomTable             map[string]*RoomWorker
	version               string
	config                *Config
	sessionSecret         []byte
	turnSecret            []byte
	turnUsernameFormat    string
	tickets               *securecookie.SecureCookie
	count                 uint64
	mutex                 sync.RWMutex
	buffers               BufferCache
	broadcastChatMessages uint64
	unicastChatMessages   uint64
}

func NewHub(version string, config *Config, sessionSecret, turnSecret, turnUsernameFormat string) *Hub {

	h := &Hub{
		connectionTable:    make(map[string]*Connection),
		userTable:          make(map[string]*User),
		roomTable:          make(map[string]*RoomWorker),
		version:            version,
		config:             config,
		sessionSecret:      []byte(sessionSecret),
		turnSecret:         []byte(turnSecret),
		turnUsernameFormat: turnUsernameFormat,
	}

	h.tickets = securecookie.New(h.sessionSecret, nil)
	h.buffers = NewBufferCache(1024, bytes.MinRead)
	return h

}

func (h *Hub) Stat(details bool) *HubStat {
	h.mutex.RLock()
	defer h.mutex.RUnlock()
	stat := &HubStat{
		Rooms:       len(h.roomTable),
		Connections: len(h.connectionTable),
		Users:       len(h.userTable),
		Count:       h.count,
		BroadcastChatMessages: atomic.LoadUint64(&h.broadcastChatMessages),
		UnicastChatMessages:   atomic.LoadUint64(&h.unicastChatMessages),
	}
	if details {
		rooms := make(map[string][]string)
		for roomid, room := range h.roomTable {
			users := make([]string, 0, len(room.connections))
			for id, _ := range room.connections {
				users = append(users, id)
			}
			rooms[roomid] = users
		}
		stat.IdsInRoom = rooms
		users := make(map[string]*DataUser)
		for userid, user := range h.userTable {
			users[userid] = user.Data()
		}
		stat.UsersById = users
		connections := make(map[string]string)
		for id, connection := range h.connectionTable {
			connections[fmt.Sprintf("%d", connection.Idx)] = id
		}
		stat.ConnectionsByIdx = connections
	}
	return stat
}

func (h *Hub) CreateTurnData(id string) *DataTurn {

	// Create turn data credentials for shared secret auth with TURN
	// server. See http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00
	// and https://code.google.com/p/rfc5766-turn-server/ REST API auth
	// and set shared secret in TURN server with static-auth-secret.
	if len(h.turnSecret) == 0 {
		return &DataTurn{}
	}
	var user string
	bar := sha256.New()
	bar.Write([]byte(id))
	id = base64.StdEncoding.EncodeToString(bar.Sum(nil))
	foo := hmac.New(sha1.New, h.turnSecret)
	expiration := int32(time.Now().Unix())+turnTTL
	switch h.turnUsernameFormat {
	case "time:id":
		user = fmt.Sprintf("%d:%s", expiration, id)
	default:
		user = fmt.Sprintf("%s:%d", id, expiration)
	}
	foo.Write([]byte(user))
	password := base64.StdEncoding.EncodeToString(foo.Sum(nil))
	return &DataTurn{user, password, turnTTL, h.config.TurnURIs}

}

func (h *Hub) EncodeTicket(key, value string) (string, error) {

	if value == "" {
		// Create new id.
		value = fmt.Sprintf("%s", securecookie.GenerateRandomKey(16))
	}
	return h.tickets.Encode(key, value)

}

func (h *Hub) DecodeTicket(key, value string) (string, error) {

	result := ""
	err := h.tickets.Decode(key, value, &result)
	return result, err

}

func (h *Hub) GetRoom(id string) *RoomWorker {

	h.mutex.RLock()
	room, ok := h.roomTable[id]
	if !ok {
		h.mutex.RUnlock()
		h.mutex.Lock()
		// need to re-check, another thread might have created the room
		// while we waited for the lock
		room, ok = h.roomTable[id]
		if !ok {
			room = NewRoomWorker(h, id)
			h.roomTable[id] = room
			h.mutex.Unlock()
			go func() {
				// Start room, this blocks until room expired.
				room.Start()
				// Cleanup room when we are done.
				h.mutex.Lock()
				defer h.mutex.Unlock()
				delete(h.roomTable, id)
				log.Printf("Cleaned up room '%s'\n", id)
			}()
		} else {
			h.mutex.Unlock()
		}
	} else {
		h.mutex.RUnlock()
	}

	return room

}

func (h *Hub) GetGlobalConnections() []*Connection {

	if h.config.globalRoomid == "" {
		return make([]*Connection, 0)
	}
	h.mutex.RLock()
	if room, ok := h.roomTable[h.config.globalRoomid]; ok {
		h.mutex.RUnlock()
		return room.GetConnections()
	} else {
		h.mutex.RUnlock()
	}
	return make([]*Connection, 0)

}

func (h *Hub) RunForAllRooms(f func(room *RoomWorker)) {

	h.mutex.RLock()
	for _, room := range h.roomTable {
		f(room)
	}
	h.mutex.RUnlock()

}

func (h *Hub) isGlobalRoomid(id string) bool {

	return id != "" && (id == h.config.globalRoomid)

}

func (h *Hub) isDefaultRoomid(id string) bool {

	return id == ""
}

func (h *Hub) registerHandler(c *Connection) {

	h.mutex.Lock()

	// Create new user instance.
	h.count++
	c.Idx = h.count
	u := &User{Id: c.Id}
	h.userTable[c.Id] = u
	c.User = u
	c.IsRegistered = true

	// Register connection or replace existing one.
	if ec, ok := h.connectionTable[c.Id]; ok {
		delete(h.connectionTable, ec.Id)
		ec.IsRegistered = false
		ec.close()
		h.connectionTable[c.Id] = c
		h.mutex.Unlock()
		//log.Printf("Register (%d) from %s: %s (existing)\n", c.Idx, c.RemoteAddr, c.Id)
	} else {
		h.connectionTable[c.Id] = c
		//fmt.Println("registered", c.Id)
		h.mutex.Unlock()
		//log.Printf("Register (%d) from %s: %s\n", c.Idx, c.RemoteAddr, c.Id)
		h.server.OnRegister(c)
	}

}

func (h *Hub) unregisterHandler(c *Connection) {

	h.mutex.Lock()
	if !c.IsRegistered {
		h.mutex.Unlock()
		return
	}
	c.close()
	delete(h.connectionTable, c.Id)
	delete(h.userTable, c.Id)
	h.mutex.Unlock()
	//log.Printf("Unregister (%d) from %s: %s\n", c.Idx, c.RemoteAddr, c.Id)
	h.server.OnUnregister(c)

}

func (h *Hub) unicastHandler(m *MessageRequest) {

	h.mutex.RLock()
	out, ok := h.connectionTable[m.To]
	h.mutex.RUnlock()
	if !ok {
		log.Println("Unicast To not found", m.To)
		return
	}
	out.send(m.Message)

}

func (h *Hub) aliveHandler(c *Connection, alive *DataAlive) {

	aliveJson := h.buffers.New()
	encoder := json.NewEncoder(aliveJson)
	err := encoder.Encode(&DataOutgoing{From: c.Id, Data: alive})
	if err != nil {
		log.Println("Alive error while encoding JSON", err)
		aliveJson.Decref()
		return
	}
	c.send(aliveJson)
	aliveJson.Decref()

}

func (h *Hub) userupdateHandler(u *UserUpdate) uint64 {

	//fmt.Println("Userupdate", u)
	h.mutex.RLock()
	user, ok := h.userTable[u.Id]
	h.mutex.RUnlock()
	var rev uint64
	if ok {
		rev = user.Update(u)
	} else {
		log.Printf("Update data for unknown user %s\n", u.Id)
	}
	return rev

}
<|endoftext|>


<commit_before>// +build darwin

package keyring

import (
	"io/ioutil"
	"os"
	"reflect"
	"testing"
)

func TestOSXKeychainDoesntExist(t *testing.T) {
	file := tmpKeychain(t)
	defer os.Remove(file)

	k, err := createKeychain(file, false, "llamas")
	if err != nil {
		t.Fatal(err)
	}
	defer releaseKeychain(k)

	if exists, _ := keychainExists(file); !exists {
		t.Fatalf("Expected existing keychain to be shown as existing")
	}

	if exists, _ := keychainExists("llamaspleasedontbeakeychainwiththisname"); exists {
		t.Fatalf("Expected non-existing keychain to NOT be shown as existing")
	}
}

func TestOSXKeychainKeyringSet(t *testing.T) {
	file := tmpKeychain(t)
	defer os.Remove(file)

	k := &keychain{path: file, passphrase: "llamas", service: "test"}
	item := Item{
		Key:         "llamas",
		Label:       "Arbitrary label",
		Description: "A freetext description",
		Data:        []byte("llamas are great"),
		TrustSelf:   true,
	}

	if err := k.Set(item); err != nil {
		t.Fatal(err)
	}

	v, err := k.Get("llamas")
	if err != nil {
		t.Fatal(err)
	}

	if string(v.Data) != string(item.Data) {
		t.Fatalf("Data stored was not the data retrieved: %q vs %q", v.Data, item.Data)
	}

	if string(v.Key) != item.Key {
		t.Fatalf("Key stored was not the data retrieved: %q vs %q", v.Key, item.Key)
	}

	if string(v.Description) != item.Description {
		t.Fatalf("Description stored was not the data retrieved: %q vs %q", v.Description, item.Description)
	}
}

func TestOSXKeychainKeyringListKeys(t *testing.T) {
	file := tmpKeychain(t)
	defer os.Remove(file)

	k := &keychain{path: file, passphrase: "llamas", service: "test"}
	keys := []string{"key1", "key2", "key3"}

	for _, key := range keys {
		if err := k.Set(Item{Key: key, Data: []byte("llamas are great")}); err != nil {
			t.Fatal(err)
		}
	}

	keys2, err := k.Keys()
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(keys, keys2) {
		t.Fatalf("Retrieved keys weren't the same: %q vs %q", keys, keys2)
	}
}

func tmpKeychain(t *testing.T) (path string) {
	file, err := ioutil.TempFile(os.TempDir(), "aws-vault-test")
	if err != nil {
		t.Fatal(err)
		return
	}
	os.Remove(file.Name())
	return file.Name()
}
<commit_msg>Fix failing tests<commit_after>// +build darwin

package keyring

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"reflect"
	"testing"
	"time"

	homedir "github.com/mitchellh/go-homedir"
)

var keychainDir string

func deleteKeychain(name string) {
	home, err := homedir.Dir()
	if err != nil {
		panic(err)
	}

	f := filepath.Join(home, "Library/Keychains", name+"-db")
	log.Printf("removing %s", f)

	if err = os.Remove(f); err != nil {
		panic(err)
	}
}

func TestOSXKeychainKeyringSet(t *testing.T) {
	name := tmpKeychain(t)
	defer deleteKeychain(name)

	k := &keychain{
		path:       name,
		passphrase: "llamas",
		service:    "test",
	}

	item := Item{
		Key:         "llamas",
		Label:       "Arbitrary label",
		Description: "A freetext description",
		Data:        []byte("llamas are great"),
		TrustSelf:   true,
	}

	if err := k.Set(item); err != nil {
		t.Fatal(err)
	}

	v, err := k.Get("llamas")
	if err != nil {
		t.Fatal(err)
	}

	if string(v.Data) != string(item.Data) {
		t.Fatalf("Data stored was not the data retrieved: %q vs %q", v.Data, item.Data)
	}

	if string(v.Key) != item.Key {
		t.Fatalf("Key stored was not the data retrieved: %q vs %q", v.Key, item.Key)
	}

	if string(v.Description) != item.Description {
		t.Fatalf("Description stored was not the data retrieved: %q vs %q", v.Description, item.Description)
	}
}

func TestOSXKeychainKeyringListKeys(t *testing.T) {
	name := tmpKeychain(t)
	defer deleteKeychain(name)

	k := &keychain{
		path:       name,
		passphrase: "llamas",
		service:    "test",
	}

	keys := []string{"key1", "key2", "key3"}

	for _, key := range keys {
		item := Item{
			Key:       key,
			Data:      []byte("llamas are great"),
			TrustSelf: true,
		}

		if err := k.Set(item); err != nil {
			t.Fatal(err)
		}
	}

	keys2, err := k.Keys()
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(keys, keys2) {
		t.Fatalf("Retrieved keys weren't the same: %q vs %q", keys, keys2)
	}
}

func tmpKeychain(t *testing.T) (name string) {
	return fmt.Sprintf("aws-vault-test-%d.keychain", time.Now().UnixNano())
}
<|endoftext|>


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

package moddeps_test

import (
	"encoding/json"
	"fmt"
	"internal/testenv"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"testing"

	"golang.org/x/mod/module"
)

type gorootModule struct {
	Path      string
	Dir       string
	hasVendor bool
}

// findGorootModules returns the list of modules found in the GOROOT source tree.
func findGorootModules(t *testing.T) []gorootModule {
	t.Helper()
	goBin := testenv.GoToolPath(t)

	goroot.once.Do(func() {
		goroot.err = filepath.Walk(runtime.GOROOT(), func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if info.Name() == "vendor" || info.Name() == "testdata" {
				return filepath.SkipDir
			}
			if info.IsDir() || info.Name() != "go.mod" {
				return nil
			}
			dir := filepath.Dir(path)

			// Use 'go list' to describe the module contained in this directory (but
			// not its dependencies).
			cmd := exec.Command(goBin, "list", "-json", "-m")
			cmd.Env = append(os.Environ(), "GO111MODULE=on")
			cmd.Dir = dir
			cmd.Stderr = new(strings.Builder)
			out, err := cmd.Output()
			if err != nil {
				return fmt.Errorf("'go list -json -m' in %s: %w\n%s", dir, err, cmd.Stderr)
			}

			var m gorootModule
			if err := json.Unmarshal(out, &m); err != nil {
				return fmt.Errorf("decoding 'go list -json -m' in %s: %w", dir, err)
			}
			if m.Path == "" || m.Dir == "" {
				return fmt.Errorf("'go list -json -m' in %s failed to populate Path and/or Dir", dir)
			}
			if _, err := os.Stat(filepath.Join(dir, "vendor")); err == nil {
				m.hasVendor = true
			}
			goroot.modules = append(goroot.modules, m)
			return nil
		})
	})

	if goroot.err != nil {
		t.Fatal(goroot.err)
	}
	return goroot.modules
}

// goroot caches the list of modules found in the GOROOT source tree.
var goroot struct {
	once    sync.Once
	modules []gorootModule
	err     error
}

// TestAllDependenciesVendored ensures that all packages imported within GOROOT
// are vendored in the corresponding GOROOT module.
//
// This property allows offline development within the Go project, and ensures
// that all dependency changes are presented in the usual code review process.
//
// This test does NOT ensure that the vendored contents match the unmodified
// contents of the corresponding dependency versions. Such as test would require
// network access, and would currently either need to copy the entire GOROOT module
// or explicitly invoke version control to check for changes.
// (See golang.org/issue/36852 and golang.org/issue/27348.)
func TestAllDependenciesVendored(t *testing.T) {
	goBin := testenv.GoToolPath(t)

	for _, m := range findGorootModules(t) {
		t.Run(m.Path, func(t *testing.T) {
			if m.hasVendor {
				// Load all of the packages in the module to ensure that their
				// dependencies are vendored. If any imported package is missing,
				// 'go list -deps' will fail when attempting to load it.
				cmd := exec.Command(goBin, "list", "-mod=vendor", "-deps", "./...")
				cmd.Env = append(os.Environ(), "GO111MODULE=on")
				cmd.Dir = m.Dir
				cmd.Stderr = new(strings.Builder)
				_, err := cmd.Output()
				if err != nil {
					t.Errorf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
					t.Logf("(Run 'go mod vendor' in %s to ensure that dependecies have been vendored.)", m.Dir)
				}
				return
			}

			// There is no vendor directory, so the module must have no dependencies.
			// Check that the list of active modules contains only the main module.
			cmd := exec.Command(goBin, "list", "-mod=mod", "-m", "all")
			cmd.Env = append(os.Environ(), "GO111MODULE=on")
			cmd.Dir = m.Dir
			cmd.Stderr = new(strings.Builder)
			out, err := cmd.Output()
			if err != nil {
				t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
			}
			if strings.TrimSpace(string(out)) != m.Path {
				t.Errorf("'%s' reported active modules other than %s:\n%s", strings.Join(cmd.Args, " "), m.Path, out)
				t.Logf("(Run 'go mod tidy' in %s to ensure that no extraneous dependencies were added, or 'go mod vendor' to copy in imported packages.)", m.Dir)
			}
		})
	}
}

// TestDependencyVersionsConsistent verifies that each module in GOROOT that
// requires a given external dependency requires the same version of that
// dependency.
//
// This property allows us to maintain a single release branch of each such
// dependency, minimizing the number of backports needed to pull in critical
// fixes. It also ensures that any bug detected and fixed in one GOROOT module
// (such as "std") is fixed in all other modules (such as "cmd") as well.
func TestDependencyVersionsConsistent(t *testing.T) {
	// Collect the dependencies of all modules in GOROOT, indexed by module path.
	type requirement struct {
		Required    module.Version
		Replacement module.Version
	}
	seen := map[string]map[requirement][]gorootModule{} // module path → requirement → set of modules with that requirement
	for _, m := range findGorootModules(t) {
		if !m.hasVendor {
			// TestAllDependenciesVendored will ensure that the module has no
			// dependencies.
			continue
		}

		// We want this test to be able to run offline and with an empty module
		// cache, so we verify consistency only for the module versions listed in
		// vendor/modules.txt. That includes all direct dependencies and all modules
		// that provide any imported packages.
		//
		// It's ok if there are undetected differences in modules that do not
		// provide imported packages: we will not have to pull in any backports of
		// fixes to those modules anyway.
		vendor, err := ioutil.ReadFile(filepath.Join(m.Dir, "vendor", "modules.txt"))
		if err != nil {
			t.Error(err)
			continue
		}

		for _, line := range strings.Split(strings.TrimSpace(string(vendor)), "\n") {
			parts := strings.Fields(line)
			if len(parts) < 3 || parts[0] != "#" {
				continue
			}

			// This line is of the form "# module version [=> replacement [version]]".
			var r requirement
			r.Required.Path = parts[1]
			r.Required.Version = parts[2]
			if len(parts) >= 5 && parts[3] == "=>" {
				r.Replacement.Path = parts[4]
				if module.CheckPath(r.Replacement.Path) != nil {
					// If the replacement is a filesystem path (rather than a module path),
					// we don't know whether the filesystem contents have changed since
					// the module was last vendored.
					//
					// Fortunately, we do not currently use filesystem-local replacements
					// in GOROOT modules.
					t.Errorf("cannot check consistency for filesystem-local replacement in module %s (%s):\n%s", m.Path, m.Dir, line)
				}

				if len(parts) >= 6 {
					r.Replacement.Version = parts[5]
				}
			}

			if seen[r.Required.Path] == nil {
				seen[r.Required.Path] = make(map[requirement][]gorootModule)
			}
			seen[r.Required.Path][r] = append(seen[r.Required.Path][r], m)
		}
	}

	// Now verify that we saw only one distinct version for each module.
	for path, versions := range seen {
		if len(versions) > 1 {
			t.Errorf("Modules within GOROOT require different versions of %s.", path)
			for r, mods := range versions {
				desc := new(strings.Builder)
				desc.WriteString(r.Required.Version)
				if r.Replacement.Path != "" {
					fmt.Fprintf(desc, " => %s", r.Replacement.Path)
					if r.Replacement.Version != "" {
						fmt.Fprintf(desc, " %s", r.Replacement.Version)
					}
				}

				for _, m := range mods {
					t.Logf("%s\trequires %v", m.Path, desc)
				}
			}
		}
	}
}
<commit_msg>cmd/internal/moddeps: skip GOROOT/pkg when locating modules<commit_after>// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package moddeps_test

import (
	"encoding/json"
	"fmt"
	"internal/testenv"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"testing"

	"golang.org/x/mod/module"
)

type gorootModule struct {
	Path      string
	Dir       string
	hasVendor bool
}

// findGorootModules returns the list of modules found in the GOROOT source tree.
func findGorootModules(t *testing.T) []gorootModule {
	t.Helper()
	goBin := testenv.GoToolPath(t)

	goroot.once.Do(func() {
		goroot.err = filepath.Walk(runtime.GOROOT(), func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if info.Name() == "vendor" || info.Name() == "testdata" {
				return filepath.SkipDir
			}
			if path == filepath.Join(runtime.GOROOT(), "pkg") {
				// GOROOT/pkg contains generated artifacts, not source code.
				//
				// In https://golang.org/issue/37929 it was observed to somehow contain
				// a module cache, so it is important to skip. (That helps with the
				// running time of this test anyway.)
				return filepath.SkipDir
			}
			if info.IsDir() || info.Name() != "go.mod" {
				return nil
			}
			dir := filepath.Dir(path)

			// Use 'go list' to describe the module contained in this directory (but
			// not its dependencies).
			cmd := exec.Command(goBin, "list", "-json", "-m")
			cmd.Env = append(os.Environ(), "GO111MODULE=on")
			cmd.Dir = dir
			cmd.Stderr = new(strings.Builder)
			out, err := cmd.Output()
			if err != nil {
				return fmt.Errorf("'go list -json -m' in %s: %w\n%s", dir, err, cmd.Stderr)
			}

			var m gorootModule
			if err := json.Unmarshal(out, &m); err != nil {
				return fmt.Errorf("decoding 'go list -json -m' in %s: %w", dir, err)
			}
			if m.Path == "" || m.Dir == "" {
				return fmt.Errorf("'go list -json -m' in %s failed to populate Path and/or Dir", dir)
			}
			if _, err := os.Stat(filepath.Join(dir, "vendor")); err == nil {
				m.hasVendor = true
			}
			goroot.modules = append(goroot.modules, m)
			return nil
		})
	})

	if goroot.err != nil {
		t.Fatal(goroot.err)
	}
	return goroot.modules
}

// goroot caches the list of modules found in the GOROOT source tree.
var goroot struct {
	once    sync.Once
	modules []gorootModule
	err     error
}

// TestAllDependenciesVendored ensures that all packages imported within GOROOT
// are vendored in the corresponding GOROOT module.
//
// This property allows offline development within the Go project, and ensures
// that all dependency changes are presented in the usual code review process.
//
// This test does NOT ensure that the vendored contents match the unmodified
// contents of the corresponding dependency versions. Such as test would require
// network access, and would currently either need to copy the entire GOROOT module
// or explicitly invoke version control to check for changes.
// (See golang.org/issue/36852 and golang.org/issue/27348.)
func TestAllDependenciesVendored(t *testing.T) {
	goBin := testenv.GoToolPath(t)

	for _, m := range findGorootModules(t) {
		t.Run(m.Path, func(t *testing.T) {
			if m.hasVendor {
				// Load all of the packages in the module to ensure that their
				// dependencies are vendored. If any imported package is missing,
				// 'go list -deps' will fail when attempting to load it.
				cmd := exec.Command(goBin, "list", "-mod=vendor", "-deps", "./...")
				cmd.Env = append(os.Environ(), "GO111MODULE=on")
				cmd.Dir = m.Dir
				cmd.Stderr = new(strings.Builder)
				_, err := cmd.Output()
				if err != nil {
					t.Errorf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
					t.Logf("(Run 'go mod vendor' in %s to ensure that dependecies have been vendored.)", m.Dir)
				}
				return
			}

			// There is no vendor directory, so the module must have no dependencies.
			// Check that the list of active modules contains only the main module.
			cmd := exec.Command(goBin, "list", "-mod=mod", "-m", "all")
			cmd.Env = append(os.Environ(), "GO111MODULE=on")
			cmd.Dir = m.Dir
			cmd.Stderr = new(strings.Builder)
			out, err := cmd.Output()
			if err != nil {
				t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
			}
			if strings.TrimSpace(string(out)) != m.Path {
				t.Errorf("'%s' reported active modules other than %s:\n%s", strings.Join(cmd.Args, " "), m.Path, out)
				t.Logf("(Run 'go mod tidy' in %s to ensure that no extraneous dependencies were added, or 'go mod vendor' to copy in imported packages.)", m.Dir)
			}
		})
	}
}

// TestDependencyVersionsConsistent verifies that each module in GOROOT that
// requires a given external dependency requires the same version of that
// dependency.
//
// This property allows us to maintain a single release branch of each such
// dependency, minimizing the number of backports needed to pull in critical
// fixes. It also ensures that any bug detected and fixed in one GOROOT module
// (such as "std") is fixed in all other modules (such as "cmd") as well.
func TestDependencyVersionsConsistent(t *testing.T) {
	// Collect the dependencies of all modules in GOROOT, indexed by module path.
	type requirement struct {
		Required    module.Version
		Replacement module.Version
	}
	seen := map[string]map[requirement][]gorootModule{} // module path → requirement → set of modules with that requirement
	for _, m := range findGorootModules(t) {
		if !m.hasVendor {
			// TestAllDependenciesVendored will ensure that the module has no
			// dependencies.
			continue
		}

		// We want this test to be able to run offline and with an empty module
		// cache, so we verify consistency only for the module versions listed in
		// vendor/modules.txt. That includes all direct dependencies and all modules
		// that provide any imported packages.
		//
		// It's ok if there are undetected differences in modules that do not
		// provide imported packages: we will not have to pull in any backports of
		// fixes to those modules anyway.
		vendor, err := ioutil.ReadFile(filepath.Join(m.Dir, "vendor", "modules.txt"))
		if err != nil {
			t.Error(err)
			continue
		}

		for _, line := range strings.Split(strings.TrimSpace(string(vendor)), "\n") {
			parts := strings.Fields(line)
			if len(parts) < 3 || parts[0] != "#" {
				continue
			}

			// This line is of the form "# module version [=> replacement [version]]".
			var r requirement
			r.Required.Path = parts[1]
			r.Required.Version = parts[2]
			if len(parts) >= 5 && parts[3] == "=>" {
				r.Replacement.Path = parts[4]
				if module.CheckPath(r.Replacement.Path) != nil {
					// If the replacement is a filesystem path (rather than a module path),
					// we don't know whether the filesystem contents have changed since
					// the module was last vendored.
					//
					// Fortunately, we do not currently use filesystem-local replacements
					// in GOROOT modules.
					t.Errorf("cannot check consistency for filesystem-local replacement in module %s (%s):\n%s", m.Path, m.Dir, line)
				}

				if len(parts) >= 6 {
					r.Replacement.Version = parts[5]
				}
			}

			if seen[r.Required.Path] == nil {
				seen[r.Required.Path] = make(map[requirement][]gorootModule)
			}
			seen[r.Required.Path][r] = append(seen[r.Required.Path][r], m)
		}
	}

	// Now verify that we saw only one distinct version for each module.
	for path, versions := range seen {
		if len(versions) > 1 {
			t.Errorf("Modules within GOROOT require different versions of %s.", path)
			for r, mods := range versions {
				desc := new(strings.Builder)
				desc.WriteString(r.Required.Version)
				if r.Replacement.Path != "" {
					fmt.Fprintf(desc, " => %s", r.Replacement.Path)
					if r.Replacement.Version != "" {
						fmt.Fprintf(desc, " %s", r.Replacement.Version)
					}
				}

				for _, m := range mods {
					t.Logf("%s\trequires %v", m.Path, desc)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>// Intended to be used with "bind -x" on bash.
// Replace the current token in the command line with a given string.
package main

import (
	"fmt"
	"github.com/omakoto/go-common/src/common"
	"github.com/omakoto/go-common/src/shell"
	"github.com/omakoto/go-common/src/textio"
	"github.com/pborman/getopt/v2"
	"io"
	"io/ioutil"
	"os"
	"strings"
)

var (
	index   = getopt.BoolLong("index", 'i', "Show indexes")
	null    = getopt.BoolLong("null", '0', "Use \\0 to terminate elements")
	useArgs = getopt.BoolLong("args", 'a', "Get command line from os.Args")
	stdin   = getopt.BoolLong("stdin", 0, "Read from stdin")
)

func main() {
	common.RunAndExit(realMain)
}

func realMain() int {
	getopt.Parse()

	eol := byte('\n')
	if *null {
		eol = 0
	}
	printWords(textio.BufferedStdout, eol, *index)

	return 0
}

func printWords(out io.Writer, eol byte, showIndex bool) {
	sh := shell.MustGetSupportedProxy()

	commandLine := ""

	if *stdin {
		in, err := ioutil.ReadAll(os.Stdin)
		common.Checke(err)
		commandLine = string(in)
	} else if *useArgs {
		commandLine = strings.Join(getopt.Args(), " ")
	} else {
		commandLine, _ = sh.GetCommandL	ine()
	}
	tokens := sh.Split(commandLine)

	eolBytes := append(make([]byte, 0), eol)

	for _, t := range tokens {
		if showIndex {
			fmt.Fprintf(out, "%d ", t.Index)
		}
		out.Write([]byte(t.Word))
		out.Write(eolBytes)
	}
}
<commit_msg>latest<commit_after>// Intended to be used with "bind -x" on bash.
// Replace the current token in the command line with a given string.
package main

import (
	"fmt"
	"github.com/omakoto/go-common/src/common"
	"github.com/omakoto/go-common/src/shell"
	"github.com/omakoto/go-common/src/textio"
	"github.com/pborman/getopt/v2"
	"io"
	"io/ioutil"
	"os"
	"strings"
)

var (
	index   = getopt.BoolLong("index", 'i', "Show indexes")
	null    = getopt.BoolLong("null", '0', "Use \\0 to terminate elements")
	useArgs = getopt.BoolLong("args", 'a', "Get command line from os.Args")
	stdin   = getopt.BoolLong("stdin", 0, "Read from stdin")
)

func main() {
	common.RunAndExit(realMain)
}

func realMain() int {
	getopt.Parse()

	eol := byte('\n')
	if *null {
		eol = 0
	}
	printWords(textio.BufferedStdout, eol, *index)

	return 0
}

func printWords(out io.Writer, eol byte, showIndex bool) {
	sh := shell.MustGetSupportedProxy()

	commandLine := ""

	if *stdin {
		in, err := ioutil.ReadAll(os.Stdin)
		common.Checke(err)
		commandLine = string(in)
	} else if *useArgs {
		commandLine = strings.Join(getopt.Args(), " ")
	} else {
		commandLine, _ = sh.GetCommandLine()
	}
	tokens := sh.Split(commandLine)

	eolBytes := append(make([]byte, 0), eol)

	for _, t := range tokens {
		if showIndex {
			fmt.Fprintf(out, "%d ", t.Index)
		}
		out.Write([]byte(t.Word))
		out.Write(eolBytes)
	}
}
<|endoftext|>


<commit_before>package main

import (
  "os"
  "fmt"
  "flag"
  "github.com/gudtech/scamp-go/scamp"
  "sync"

  "github.com/gudtech/retailops-sdk/verify/verify_service"
  "github.com/gudtech/retailops-sdk/verify/sdk_actions"
)

var gtsoaConfigPath = flag.String("config", "/etc/GTSOA/soa.conf", "path to the GTSOA soa.conf")
var registrationTicket = flag.String("registration-ticket", "/backplane/etc/endorsements/gtuser-sdk_service.ticket", "path to gtuser sdk_service ticket")

func main() {
  var err error
  flag.Parse()

  fmt.Println("loading config from",*gtsoaConfigPath)

  err = scamp.Initialize(*gtsoaConfigPath)
  if err != nil {
    fmt.Println("failed to load scamp config:",err.Error())
    os.Exit(1)
  }

  verifierSvc,err := scamp.NewService("main","127.0.0.1:0","sdk_service")
  if err != nil {
    scamp.Error.Printf("could not create service: `%s`", err.Error())
    os.Exit(1)
  }
  verify_service.TicketPath = *registrationTicket
  verifierSvc.Register("Integration.Channel.certify", verify_service.VerifyAction)

  callbackSvc,err := scamp.NewService("channelmodule", "127.0.0.1:0","sdk_service")
  if err != nil {
    scamp.Error.Printf("could not create serivce: `%s`", err.Error())
    os.Exit(1)
  }
  // callbackSvc.Register("SDK.items_returned",sdk_actions.OrderReturnedV1) // , SDK callback: order_returned_v1
  // callbackSvc.Register("SDK.shipment_submit",sdk_actions.OrderShipmentSubmitV1) // , SDK callback: order_shipment_submit_v1
  // callbackSvc.Register("SDK.order_cancel",sdk_actions.OrderCancelV1) // , SDK callback: order_cancel_v1
  // callbackSvc.Register("SDK.order_complete",sdk_actions.OrderCompleteV1) // , SDK callback: order_complete_v1
  // callbackSvc.Register("SDK.capture_channel_payments",sdk_actions.OrderSettlePaymentV1) // , SDK callback: order_settle_payment_v1
  // callbackSvc.Register("SDK.orderpull.order_ack",sdk_actions.OrderAcknowledgeV1) // , SDK callback: order_acknowledge_v1
  callbackSvc.Register("SDK.orderpull.order_fetch",sdk_actions.OrderPullV1) // , SDK callback: order_pull_v1
  // callbackSvc.Register("SDK.catpush_config",sdk_actions.CatalogGetConfigV1) // , SDK callback: catalog_get_config_v1
  // callbackSvc.Register("SDK.catpush_transmit",sdk_actions.CatalogPushV1) // , SDK callback: catalog_push_v1
  callbackSvc.Register("SDK.inventory.invpush_transmit",sdk_actions.InventoryPushV1) // , SDK callback: inventory_push_v1
  // callbackSvc.Register("SDK.writeback",sdk_actions.OrderUpdateV1) // , SDK callback: order_update_v1

  announcer,err := scamp.NewDiscoveryAnnouncer()
  if err != nil {
    scamp.Error.Printf("failed to create announcer: `%s`", err)
    return
  }

  announcer.Track(verifierSvc)
  announcer.Track(callbackSvc)
  go announcer.AnnounceLoop()

  var wg sync.WaitGroup
  wg.Add(1)
  go func() {
    callbackSvc.Run()
    wg.Done()
  }()

  wg.Add(1)
  go func(){
    verifierSvc.Run()
    wg.Done()
  }()

  wg.Wait()
}
<commit_msg>changed service IP to 0.0.0.0:0<commit_after>package main

import (
  "os"
  "fmt"
  "flag"
  "github.com/gudtech/scamp-go/scamp"
  "sync"

  "github.com/gudtech/retailops-sdk/verify/verify_service"
  "github.com/gudtech/retailops-sdk/verify/sdk_actions"
)

var gtsoaConfigPath = flag.String("config", "/etc/GTSOA/soa.conf", "path to the GTSOA soa.conf")
var registrationTicket = flag.String("registration-ticket", "/backplane/etc/endorsements/gtuser-sdk_service.ticket", "path to gtuser sdk_service ticket")

func main() {
  var err error
  flag.Parse()

  fmt.Println("loading config from",*gtsoaConfigPath)

  err = scamp.Initialize(*gtsoaConfigPath)
  if err != nil {
    fmt.Println("failed to load scamp config:",err.Error())
    os.Exit(1)
  }

  verifierSvc,err := scamp.NewService("main","0.0.0.0:0","sdk_service")
  if err != nil {
    scamp.Error.Printf("could not create service: `%s`", err.Error())
    os.Exit(1)
  }
  verify_service.TicketPath = *registrationTicket
  verifierSvc.Register("Integration.Channel.certify", verify_service.VerifyAction)

  callbackSvc,err := scamp.NewService("channelmodule", "0.0.0.0:0","sdk_service")
  if err != nil {
    scamp.Error.Printf("could not create serivce: `%s`", err.Error())
    os.Exit(1)
  }
  // callbackSvc.Register("SDK.items_returned",sdk_actions.OrderReturnedV1) // , SDK callback: order_returned_v1
  // callbackSvc.Register("SDK.shipment_submit",sdk_actions.OrderShipmentSubmitV1) // , SDK callback: order_shipment_submit_v1
  // callbackSvc.Register("SDK.order_cancel",sdk_actions.OrderCancelV1) // , SDK callback: order_cancel_v1
  // callbackSvc.Register("SDK.order_complete",sdk_actions.OrderCompleteV1) // , SDK callback: order_complete_v1
  // callbackSvc.Register("SDK.capture_channel_payments",sdk_actions.OrderSettlePaymentV1) // , SDK callback: order_settle_payment_v1
  // callbackSvc.Register("SDK.orderpull.order_ack",sdk_actions.OrderAcknowledgeV1) // , SDK callback: order_acknowledge_v1
  callbackSvc.Register("SDK.orderpull.order_fetch",sdk_actions.OrderPullV1) // , SDK callback: order_pull_v1
  // callbackSvc.Register("SDK.catpush_config",sdk_actions.CatalogGetConfigV1) // , SDK callback: catalog_get_config_v1
  // callbackSvc.Register("SDK.catpush_transmit",sdk_actions.CatalogPushV1) // , SDK callback: catalog_push_v1
  callbackSvc.Register("SDK.inventory.invpush_transmit",sdk_actions.InventoryPushV1) // , SDK callback: inventory_push_v1
  // callbackSvc.Register("SDK.writeback",sdk_actions.OrderUpdateV1) // , SDK callback: order_update_v1

  announcer,err := scamp.NewDiscoveryAnnouncer()
  if err != nil {
    scamp.Error.Printf("failed to create announcer: `%s`", err)
    return
  }

  announcer.Track(verifierSvc)
  announcer.Track(callbackSvc)
  go announcer.AnnounceLoop()

  var wg sync.WaitGroup
  wg.Add(1)
  go func() {
    callbackSvc.Run()
    wg.Done()
  }()

  wg.Add(1)
  go func(){
    verifierSvc.Run()
    wg.Done()
  }()

  wg.Wait()
}
<|endoftext|>


<commit_before>package command

import (
	"crypto/rand"
	"crypto/rsa"
	"fmt"
	"log"

	"github.com/lestrrat/go-jwx/jwk"
	"github.com/nabeken/aaa/agent"
	"github.com/pkg/errors"
)

type CertCommand struct {
	CommonName string   `long:"cn" description:"CommonName to be issued"`
	Domains    []string `long:"domain" description:"Domains to be issued as Subject Alternative Names"`
	CreateKey  bool     `long:"create-key" description:"Create a new keypair"`
	RSAKeySize int      `long:"rsa-key-size" description:"Size of the RSA key, only used if create-key is specified. (allowed: 2048 / 4096)" default:"4096"`
}

func (c *CertCommand) Execute(args []string) error {
	store, err := NewStore(Options.Email, Options.S3Bucket, Options.S3KMSKeyID)
	if err != nil {
		return errors.Wrap(err, "failed to initialize the store")
	}

	if c.RSAKeySize != 4096 && c.RSAKeySize != 2048 {
		return errors.New("Key size must be 4096 or 2048")
	}

	return (&CertService{
		CommonName: c.CommonName,
		Domains:    c.Domains,
		CreateKey:  c.CreateKey,
		RSAKeySize: c.RSAKeySize,
		Store:      store,
	}).Run()
}

type CertService struct {
	CommonName string
	Domains    []string
	CreateKey  bool
	RSAKeySize int
	Store      *agent.Store
}

func (svc *CertService) Run() error {
	log.Print("INFO: now issuing certificate...")

	// trying to load the key
	key, err := svc.Store.LoadCertKey(svc.CommonName)
	if err != nil {
		if err != agent.ErrFileNotFound {
			return errors.Wrap(err, "failed to load the key")
		}

		// we have to create a new keypair anyway
		svc.CreateKey = true
	}

	// Creating private key for cert
	var privateKey *rsa.PrivateKey
	if svc.CreateKey {
		log.Printf("INFO: creating %d bit new private key...", svc.RSAKeySize)
		certPrivkey, err := rsa.GenerateKey(rand.Reader, svc.RSAKeySize)
		if err != nil {
			return errors.Wrap(err, "failed to generate a keypair")
		}

		certPrivkeyJWK, err := jwk.New(certPrivkey)
		if err != nil {
			return errors.Wrap(err, "failed to create a JWK")
		}

		// storing private key for certificate
		if err := svc.Store.SaveCertKey(svc.CommonName, certPrivkeyJWK); err != nil {
			return errors.Wrap(err, "failed to store the JWK")
		}

		privateKey = certPrivkey
	} else {
		log.Print("INFO: using the existing private key...")
		pkey, err := key.Materialize()
		if err != nil {
			return errors.Wrap(err, "failed to materialize the key")
		}

		rsaPrivKey, ok := pkey.(*rsa.PrivateKey)
		if !ok {
			return fmt.Errorf("aaa: key is not *rsa.PrivateKey but %v", pkey)
		}

		privateKey = rsaPrivKey
	}

	// Creating CSR
	der, err := agent.CreateCertificateRequest(privateKey, svc.CommonName, svc.Domains...)
	if err != nil {
		return errors.Wrap(err, "failed to create a CSR")
	}

	// initialize client here
	client := agent.NewClient(DirectoryURL(), svc.Store)
	if err := client.Init(); err != nil {
		return errors.Wrap(err, "failed to initialize the client")
	}

	// Issue new-cert request
	certURL, err := client.NewCertificate(der)
	if err != nil {
		return errors.Wrap(err, "failed to issue the certificate")
	}

	log.Printf("INFO: certificate will be available at %s", certURL)

	issuerCert, myCert, err := client.GetCertificate(certURL)
	if err != nil {
		return errors.Wrap(err, "failed to get the certificate")
	}

	if err := svc.Store.SaveCert(svc.CommonName, issuerCert, myCert); err != nil {
		return errors.Wrap(err, "failed to store the certificate")
	}

	log.Print("INFO: certificate is successfully saved")

	return nil
}
<commit_msg>cert: checking the key length in CertService<commit_after>package command

import (
	"crypto/rand"
	"crypto/rsa"
	"fmt"
	"log"

	"github.com/lestrrat/go-jwx/jwk"
	"github.com/nabeken/aaa/agent"
	"github.com/pkg/errors"
)

type CertCommand struct {
	CommonName string   `long:"cn" description:"CommonName to be issued"`
	Domains    []string `long:"domain" description:"Domains to be issued as Subject Alternative Names"`
	CreateKey  bool     `long:"create-key" description:"Create a new keypair"`
	RSAKeySize int      `long:"rsa-key-size" description:"Size of the RSA key, only used if create-key is specified. (allowed: 2048 / 4096)" default:"4096"`
}

func (c *CertCommand) Execute(args []string) error {
	store, err := NewStore(Options.Email, Options.S3Bucket, Options.S3KMSKeyID)
	if err != nil {
		return errors.Wrap(err, "failed to initialize the store")
	}

	return (&CertService{
		CommonName: c.CommonName,
		Domains:    c.Domains,
		CreateKey:  c.CreateKey,
		RSAKeySize: c.RSAKeySize,
		Store:      store,
	}).Run()
}

type CertService struct {
	CommonName string
	Domains    []string
	CreateKey  bool
	RSAKeySize int
	Store      *agent.Store
}

func (svc *CertService) Run() error {
	log.Print("INFO: now issuing certificate...")

	// trying to load the key
	key, err := svc.Store.LoadCertKey(svc.CommonName)
	if err != nil {
		if err != agent.ErrFileNotFound {
			return errors.Wrap(err, "failed to load the key")
		}

		// we have to create a new keypair anyway
		svc.CreateKey = true
	}

	// Creating private key for cert
	var privateKey *rsa.PrivateKey
	if svc.CreateKey {
		if svc.RSAKeySize != 4096 && svc.RSAKeySize != 2048 {
			return errors.New("key size must be 4096 or 2048")
		}

		log.Printf("INFO: creating %d bit new private key...", svc.RSAKeySize)
		certPrivkey, err := rsa.GenerateKey(rand.Reader, svc.RSAKeySize)
		if err != nil {
			return errors.Wrap(err, "failed to generate a keypair")
		}

		certPrivkeyJWK, err := jwk.New(certPrivkey)
		if err != nil {
			return errors.Wrap(err, "failed to create a JWK")
		}

		// storing private key for certificate
		if err := svc.Store.SaveCertKey(svc.CommonName, certPrivkeyJWK); err != nil {
			return errors.Wrap(err, "failed to store the JWK")
		}

		privateKey = certPrivkey
	} else {
		log.Print("INFO: using the existing private key...")
		pkey, err := key.Materialize()
		if err != nil {
			return errors.Wrap(err, "failed to materialize the key")
		}

		rsaPrivKey, ok := pkey.(*rsa.PrivateKey)
		if !ok {
			return fmt.Errorf("aaa: key is not *rsa.PrivateKey but %v", pkey)
		}

		privateKey = rsaPrivKey
	}

	// Creating CSR
	der, err := agent.CreateCertificateRequest(privateKey, svc.CommonName, svc.Domains...)
	if err != nil {
		return errors.Wrap(err, "failed to create a CSR")
	}

	// initialize client here
	client := agent.NewClient(DirectoryURL(), svc.Store)
	if err := client.Init(); err != nil {
		return errors.Wrap(err, "failed to initialize the client")
	}

	// Issue new-cert request
	certURL, err := client.NewCertificate(der)
	if err != nil {
		return errors.Wrap(err, "failed to issue the certificate")
	}

	log.Printf("INFO: certificate will be available at %s", certURL)

	issuerCert, myCert, err := client.GetCertificate(certURL)
	if err != nil {
		return errors.Wrap(err, "failed to get the certificate")
	}

	if err := svc.Store.SaveCert(svc.CommonName, issuerCert, myCert); err != nil {
		return errors.Wrap(err, "failed to store the certificate")
	}

	log.Print("INFO: certificate is successfully saved")

	return nil
}
<|endoftext|>


<commit_before>package git

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	"github.com/google/go-github/github"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"golang.org/x/net/context"
)

func TestParseRepositoryName(t *testing.T) {
	owner, repo := ParseRepositoryName("test/me")
	assert.Equal(t, owner, "test")
	assert.Equal(t, repo, "me")
}

func TestNewGithubRepositories_WithToken(t *testing.T) {
	ctx := context.WithValue(context.Background(), GithubToken, "secret_token")

	r, err := NewGithubRepositories(ctx)
	require.NoError(t, err, "Expected NewGithubRepositories to succeed")
	assert.NotNil(t, r, "Expected NewGithubRepositories to return new instance")
}

func TestNewGithubRepositories_NoToken(t *testing.T) {
	_, err := NewGithubRepositories(context.Background())
	assert.Error(t, err, "Expected NewGithubRepositories to return an error")
}

func TestNewGithubRepositories_EmptyToken(t *testing.T) {
	ctx := context.WithValue(context.Background(), GithubToken, "")

	_, err := NewGithubRepositories(ctx)
	assert.Error(t, err, "Expected NewGithubRepositories to return an error")
}

func TestGithubRepositoriesAll_SingleRepository_DefaultFields(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `[{
                    "full_name": "user1/repo1",
                    "git_url": "git@github.com:user1/repo1.git"
                }]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	if assert.Len(t, repos, 1) {
		repo := repos[0]
		assert.Equal(t, repo.FullName, "user1/repo1")
		assert.Equal(t, repo.Master, "master")
		assert.Empty(t, repo.Description)
		assert.Empty(t, repo.GitURL)
		assert.Empty(t, repo.HTMLURL)
	}
}

func TestGithubRepositoriesAll_SingleRepository_AllFields(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `[{
                    "full_name": "user1/repo1",
                    "description": "Repo1",
                    "default_branch": "production",
                    "git_url": "git@github.com:user1/repo1.git",
                    "html_url": "https://github.com/user1/repo1"
                }]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	if assert.Len(t, repos, 1) {
		repo := repos[0]
		assert.Equal(t, repo.FullName, "user1/repo1")
		assert.Equal(t, repo.Description, "Repo1")
		assert.Equal(t, repo.Master, "production")
		assert.Empty(t, repo.GitURL)
	}
}

func TestGithubRepositoriesAll_MultipleRepositories(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `[{
                    "full_name": "user1/repo1",
                    "git_url": "https://github.com/user1/repo1"
                },{
                    "full_name": "user2/repo2",
                    "git_url": "https://github.com/user2/repo2"
                }]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	assert.Len(t, repos, 2)
}

func TestGithubRepositoriesAll_SkipWithoutGitURL(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `[{
                    "full_name": "user1/repo1"
                },{
                    "full_name": "user2/repo2",
                    "git_url": "git:git@github.com:user2/repo2.git"
                }]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	if assert.Len(t, repos, 1, "Should exclude one repository without git_url") {
		assert.Equal(t, repos[0].FullName, "user2/repo2")
	}
}

func TestGithubRepositoriesAll_SkipWithoutFullName(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `[{
                    "full_name": "user1/repo1",
                    "git_url": "git:git@github.com:user1/repo1.git"
                },{
                    "git_url": "git:git@github.com:user2/repo2.git"
                }]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	if assert.Len(t, repos, 1, "Should exclude one repository without full_name") {
		assert.Equal(t, repos[0].FullName, "user1/repo1")
	}
}

func TestGithubRepositoriesAll_HandlePagination(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		if page := r.FormValue("page"); page == "" || page == "1" {
			perPage := r.FormValue("per_page")
			if perPage == "" {
				perPage = "30"
			}

			w.Header().Set("Link", fmt.Sprintf(`<https://api.github.com/user/repos?page=2&per_page=%s>; rel="next"`, perPage))
		}

		fmt.Fprint(w, `[{"full_name": "user1/repo1","git_url": "git:git@github.com:user1/repo1.git"}]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	assert.Len(t, repos, 2)
}

func TestGithubRepositoriesGet_RepositoryExists(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	// Get repo
	mux.HandleFunc("/repos/user1/repo1", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{
		    "full_name": "user1/repo1",
		    "description":
		    "Test repo",
		    "default_branch":"production",
		    "git_url":"git:git@github.com:user1/repo1.git",
		    "html_url": "https://github.com/user1/repo1"
		}`)
	})
	// Get branch
	mux.HandleFunc("/repos/user1/repo1/branches/production", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"name":"production","commit":{"sha":"abc123"}}`)
	})
	// Get git commit
	mux.HandleFunc("/repos/user1/repo1/git/commits/abc123", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{
		    "author":{"name":"Jon Doe","date":"2011-04-14T16:00:49Z"},
		    "committer":{"name":"Doppel Ganger","date":"2016-04-14T16:00:00Z"},
		    "message":"Commit message",
		    "sha":"abc123"
		}`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repo, err := githubRepos.Get("user1/repo1")
	require.NoError(t, err)

	assert.Equal(t, repo.FullName, "user1/repo1")
	assert.Equal(t, repo.GitURL, "git:git@github.com:user1/repo1.git")
}

func TestGithubRepositoriesGet_NotFound(t *testing.T) {
	ctx, _, teardown := setup()
	defer teardown()

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	_, err = githubRepos.Get("user1/repo1")
	assert.Equal(t, err, ErrorNotFound)
}

func setup() (ctx context.Context, mux *http.ServeMux, teardownFn func()) {
	mux = http.NewServeMux()
	server := httptest.NewServer(mux)

	client := github.NewClient(nil)
	url, _ := url.Parse(server.URL)
	client.BaseURL = url

	ctx = context.Background()
	ctx = context.WithValue(ctx, GithubToken, "secret_token")
	ctx = context.WithValue(ctx, httpClient, client)

	return ctx, mux, server.Close
}
<commit_msg>Add test for GithubRepositories.Track<commit_after>package git

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	"github.com/google/go-github/github"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"golang.org/x/net/context"
)

func TestParseRepositoryName(t *testing.T) {
	owner, repo := ParseRepositoryName("test/me")
	assert.Equal(t, owner, "test")
	assert.Equal(t, repo, "me")
}

func TestNewGithubRepositories_WithToken(t *testing.T) {
	ctx := context.WithValue(context.Background(), GithubToken, "secret_token")

	r, err := NewGithubRepositories(ctx)
	require.NoError(t, err, "Expected NewGithubRepositories to succeed")
	assert.NotNil(t, r, "Expected NewGithubRepositories to return new instance")
}

func TestNewGithubRepositories_NoToken(t *testing.T) {
	_, err := NewGithubRepositories(context.Background())
	assert.Error(t, err, "Expected NewGithubRepositories to return an error")
}

func TestNewGithubRepositories_EmptyToken(t *testing.T) {
	ctx := context.WithValue(context.Background(), GithubToken, "")

	_, err := NewGithubRepositories(ctx)
	assert.Error(t, err, "Expected NewGithubRepositories to return an error")
}

func TestGithubRepositoriesAll_SingleRepository_DefaultFields(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `[{
                    "full_name": "user1/repo1",
                    "git_url": "git@github.com:user1/repo1.git"
                }]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	if assert.Len(t, repos, 1) {
		repo := repos[0]
		assert.Equal(t, repo.FullName, "user1/repo1")
		assert.Equal(t, repo.Master, "master")
		assert.Empty(t, repo.Description)
		assert.Empty(t, repo.GitURL)
		assert.Empty(t, repo.HTMLURL)
	}
}

func TestGithubRepositoriesAll_SingleRepository_AllFields(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `[{
                    "full_name": "user1/repo1",
                    "description": "Repo1",
                    "default_branch": "production",
                    "git_url": "git@github.com:user1/repo1.git",
                    "html_url": "https://github.com/user1/repo1"
                }]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	if assert.Len(t, repos, 1) {
		repo := repos[0]
		assert.Equal(t, repo.FullName, "user1/repo1")
		assert.Equal(t, repo.Description, "Repo1")
		assert.Equal(t, repo.Master, "production")
		assert.Empty(t, repo.GitURL)
	}
}

func TestGithubRepositoriesAll_MultipleRepositories(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `[{
                    "full_name": "user1/repo1",
                    "git_url": "https://github.com/user1/repo1"
                },{
                    "full_name": "user2/repo2",
                    "git_url": "https://github.com/user2/repo2"
                }]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	assert.Len(t, repos, 2)
}

func TestGithubRepositoriesAll_SkipWithoutGitURL(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `[{
                    "full_name": "user1/repo1"
                },{
                    "full_name": "user2/repo2",
                    "git_url": "git:git@github.com:user2/repo2.git"
                }]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	if assert.Len(t, repos, 1, "Should exclude one repository without git_url") {
		assert.Equal(t, repos[0].FullName, "user2/repo2")
	}
}

func TestGithubRepositoriesAll_SkipWithoutFullName(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `[{
                    "full_name": "user1/repo1",
                    "git_url": "git:git@github.com:user1/repo1.git"
                },{
                    "git_url": "git:git@github.com:user2/repo2.git"
                }]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	if assert.Len(t, repos, 1, "Should exclude one repository without full_name") {
		assert.Equal(t, repos[0].FullName, "user1/repo1")
	}
}

func TestGithubRepositoriesAll_HandlePagination(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
		if page := r.FormValue("page"); page == "" || page == "1" {
			perPage := r.FormValue("per_page")
			if perPage == "" {
				perPage = "30"
			}

			w.Header().Set("Link", fmt.Sprintf(`<https://api.github.com/user/repos?page=2&per_page=%s>; rel="next"`, perPage))
		}

		fmt.Fprint(w, `[{"full_name": "user1/repo1","git_url": "git:git@github.com:user1/repo1.git"}]`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repos, err := githubRepos.All()
	require.NoError(t, err)

	assert.Len(t, repos, 2)
}

func TestGithubRepositoriesGet_RepositoryExists(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	// Get repo
	mux.HandleFunc("/repos/user1/repo1", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{
		    "full_name": "user1/repo1",
		    "description":
		    "Test repo",
		    "default_branch":"production",
		    "git_url":"git:git@github.com:user1/repo1.git",
		    "html_url": "https://github.com/user1/repo1"
		}`)
	})
	// Get branch
	mux.HandleFunc("/repos/user1/repo1/branches/production", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"name":"production","commit":{"sha":"abc123"}}`)
	})
	// Get git commit
	mux.HandleFunc("/repos/user1/repo1/git/commits/abc123", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{
		    "author":{"name":"Jon Doe","date":"2011-04-14T16:00:49Z"},
		    "committer":{"name":"Doppel Ganger","date":"2016-04-14T16:00:00Z"},
		    "message":"Commit message",
		    "sha":"abc123"
		}`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	repo, err := githubRepos.Get("user1/repo1")
	require.NoError(t, err)

	assert.Equal(t, repo.FullName, "user1/repo1")
	assert.Equal(t, repo.GitURL, "git:git@github.com:user1/repo1.git")
}

func TestGithubRepositoriesGet_NotFound(t *testing.T) {
	ctx, _, teardown := setup()
	defer teardown()

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	_, err = githubRepos.Get("user1/repo1")
	assert.Equal(t, err, ErrorNotFound)
}

func TestGithubRepositoriesTrack(t *testing.T) {
	ctx, mux, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/user1/repo1/hooks", func(w http.ResponseWriter, r *http.Request) {
		require.Equal(t, r.Method, "POST")

		body, err := ioutil.ReadAll(r.Body)
		require.NoError(t, err)

		var hook github.Hook
		require.NoError(t, json.Unmarshal(body, &hook), string(body))

		assert.Equal(t, *hook.Name, "web")
		assert.Contains(t, hook.Events, "push")
		assert.Equal(t, hook.Config["url"], "http://example.com/cb")
		assert.True(t, *hook.Active)

		fmt.Fprint(w, `{"id":1}`)
	})

	githubRepos, err := NewGithubRepositories(ctx)
	require.NoError(t, err)

	err = githubRepos.Track("user1/repo1", "http://example.com/cb")
	require.NoError(t, err)
}

func setup() (ctx context.Context, mux *http.ServeMux, teardownFn func()) {
	mux = http.NewServeMux()
	server := httptest.NewServer(mux)

	client := github.NewClient(nil)
	url, _ := url.Parse(server.URL)
	client.BaseURL = url

	ctx = context.Background()
	ctx = context.WithValue(ctx, GithubToken, "secret_token")
	ctx = context.WithValue(ctx, httpClient, client)

	return ctx, mux, server.Close
}
<|endoftext|>


<commit_before>package main

import (
	"C"
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

func call_post_req(apiName string, concurrentOn string, apiData string, client *http.Client, respo chan<- string, quit <-chan bool) {
	data := make(map[string]string)
	data["data"] = apiData
	data["pk"] = concurrentOn
	dataByte, _ := json.Marshal(data)
	req, _ := http.NewRequest("POST", apiName, bytes.NewBuffer(dataByte))
	resp, _ := client.Do(req)
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	var response map[string]interface{}
	json.Unmarshal([]byte(body), &response)
	select{
	case <-quit:
		return
	case <-time.Tick((1 * time.Millisecond)):
		respo <- string(body)
	}
	return
}

//export call_api
func call_api(apiNameC *C.char, stringDataC *C.char, concurrencyOnListC *C.char) *C.char {
	apiName := C.GoString(apiNameC)
	stringData := C.GoString(stringDataC)
	concurrencyOnString := C.GoString(concurrencyOnListC)
	concurrencyOnList := strings.Split(concurrencyOnString, ",")
	respo := make(chan string, len(concurrencyOnList))
	quit := make(chan bool, len(concurrencyOnList))
	client := &http.Client{}
	for _, value := range concurrencyOnList {
		go call_post_req(apiName, value, stringData, client, respo, quit)
		//call_post_req(apiName, value, stringData, client, respo)
	}
	doneStr := ""
	tick := time.Tick(10 * time.Second)
	flag := true
	for flag {
		select{
		case s := <-respo:
			doneStr +=s
		case <-tick:
			for i := 0; i < len(concurrencyOnList); i++ {
				quit <- true
			}
			fmt.Println("Timeout")
			doneStr += "--Timeout--"
			flag = false
			break
		}
	}
	close(respo)
	defer close(quit)
	fmt.Println("GO END")
	return C.CString(doneStr)
}

func main() {}
<commit_msg>no waiting if timout never happens<commit_after>package main

import (
	"C"
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

func call_post_req(apiName string, concurrentOn string, apiData string, client *http.Client, respo chan<- string, quit <-chan bool) {
	data := make(map[string]string)
	data["data"] = apiData
	data["pk"] = concurrentOn
	dataByte, _ := json.Marshal(data)
	req, _ := http.NewRequest("POST", apiName, bytes.NewBuffer(dataByte))
	resp, _ := client.Do(req)
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	var response map[string]interface{}
	json.Unmarshal([]byte(body), &response)
	select{
	case <-quit:
		return
	case <-time.Tick((1 * time.Millisecond)):
		respo <- string(body)
	}
	return
}

//export call_api
func call_api(apiNameC *C.char, stringDataC *C.char, concurrencyOnListC *C.char) *C.char {
	apiName := C.GoString(apiNameC)
	stringData := C.GoString(stringDataC)
	concurrencyOnString := C.GoString(concurrencyOnListC)
	concurrencyOnList := strings.Split(concurrencyOnString, ",")
	concurrentOnCount := len(concurrencyOnList)
	respo := make(chan string, concurrentOnCount)
	quit := make(chan bool, concurrentOnCount)
	client := &http.Client{}
	for _, value := range concurrencyOnList {
		go call_post_req(apiName, value, stringData, client, respo, quit)
		//call_post_req(apiName, value, stringData, client, respo)
	}
	doneStr := ""
	tick := time.Tick(10 * time.Second)
	flag := true
	for i := 0; flag && i < concurrentOnCount; i++ {
		select{
		case s := <-respo:
			doneStr +=s
		case <-tick:
			for i := 0; i < concurrentOnCount; i++ {
				quit <- true
			}
			fmt.Println("Timeout")
			doneStr += "--Timeout--"
			flag = false
			break
		}
	}
	close(respo)
	defer close(quit)
	fmt.Println("GO END")
	return C.CString(doneStr)
}

func main() {}
<|endoftext|>