<commit_before>package trident

import (
	"errors"
	"time"
	"trident.li/keyval"
	pf "trident.li/pitchfork/lib"
)

type TriGroup interface {
	pf.PfGroup
	Add_default_attestations(ctx pf.PfCtx) (err error)
	GetVouch_adminonly() bool
	GetAttestations() (output []TriGroupAttestation, err error)
	GetAttestationsKVS() (kvs keyval.KeyVals, err error)
}

type TriGroupS struct {
	pf.PfGroup
	Please_vouch    bool   `label:"Please Vouch" pfset:"group_admin" hint:"Members must vouch before becoming active"`
	Vouch_adminonly bool   `label:"Vouch group admins only" pfset:"group_admin" hint:"Only adminstators may Vouvh"`
	Min_invouch     int    `label:"Minimum Inbound Vouches" pfset:"group_admin" hint:"Number of incoming vouches required to vett."`
	Min_outvouch    int    `label:"Minimum Outbound Vouches" pfset:"group_admin" hint:"Number of outgoing vouches required"`
	Target_invouch  int    `label:"Target Invouches" pfset:"group_admin"`
	Max_inactivity  string `label:"Maximum Inactivity" pfset:"group_admin"`
	Can_time_out    bool   `label:"Can Time Out" pfset:"group_admin"`
	Max_vouchdays   int    `label:"Maximum Vouch Days" pfset:"group_admin"`
	Idle_guard      string `label:"Idle Guard" pfset:"group_admin"`
	Nom_enabled     bool   `label:"Nominations Enabled" pfset:"group_admin"`
}

type TriGroupMember interface {
	pf.PfGroupMember
	GetVouchesFor() int
	GetVouchesBy() int
	GetVouchesForMe() int
	GetVouchesByMe() int
}

type TriGroupMemberS struct {
	pf.PfGroupMember
	VouchesFor   int
	VouchesBy    int
	VouchesForMe int
	VouchesByMe  int
}

func (o *TriGroupMemberS) GetVouchesFor() int {
	return o.VouchesFor
}

func (o *TriGroupMemberS) GetVouchesBy() int {
	return o.VouchesBy
}

func (o *TriGroupMemberS) GetVouchesForMe() int {
	return o.VouchesForMe
}

func (o *TriGroupMemberS) GetVouchesByMe() int {
	return o.VouchesByMe
}

/* Don't call directly, use ctx.NewGroup() */
func NewTriGroup() pf.PfGroup {
	return &TriGroupS{PfGroup: pf.NewPfGroup()}
}

func NewTriGroupMember() TriGroupMember {
	pfg := pf.NewPfGroupMember()
	return &TriGroupMemberS{PfGroupMember: pfg}
}

func (grp *TriGroupS) GetVouch_adminonly() bool {
	return grp.Vouch_adminonly
}

func (grp *TriGroupS) GetMembers(search string, username string, offset int, max int, nominated bool, inclhidden bool, exact bool) (members []pf.PfGroupMember, err error) {
	var rows *pf.Rows

	grpn := grp.GetGroupName()

	members = nil

	ord := "ORDER BY m.descr"

	q := "SELECT m.ident, " +
		"m.descr, " +
		"m.affiliation, " +
		"mt.admin, " +
		"mt.state, " +
		"me.email, " +
		"me.pgpkey_id, " +
		"  EXTRACT(day FROM now() - m.activity) as activity, " +
		"  tel_info, " +
		"  sms_info, " +
		"  m.airport, " +
		"  COALESCE(for_vouches.num, 0) AS vouches_for, " +
		"  COALESCE(for_me_vouches.num, 0) AS vouches_for_me, " +
		"  COALESCE(by_vouches.num, 0) AS vouches_by, " +
		"  COALESCE(by_me_vouches.num, 0) AS vouches_by_me " +
		"FROM member_trustgroup mt " +
		"INNER JOIN trustgroup grp ON (mt.trustgroup = grp.ident) " +
		"INNER JOIN member m ON (mt.member = m.ident) " +
		"INNER JOIN member_state ms ON (ms.ident = mt.state) " +
		"INNER JOIN member_email me ON (me.member = m.ident) " +
		"LEFT OUTER JOIN ( " +
		"  SELECT 'for' AS dir, mv.vouchee AS member, COUNT(*) AS num " +
		"  FROM member_vouch mv " +
		"  WHERE mv.trustgroup = $1 " +
		"  AND mv.positive " +
		"  GROUP BY mv.vouchee " +
		") as for_vouches on (m.ident = for_vouches.member) " +
		"LEFT OUTER JOIN ( " +
		"  SELECT 'by' AS dir, mv.vouchor AS member, COUNT(*) AS num " +
		"  FROM member_vouch mv " +
		"  WHERE mv.trustgroup = $1 " +
		"  AND mv.positive " +
		"  GROUP BY mv.vouchor " +
		") as by_vouches on (m.ident = by_vouches.member) " +
		"LEFT OUTER JOIN ( " +
		"  SELECT 'for_me' AS dir, mv.vouchor AS member, COUNT(*) AS num " +
		"  FROM member_vouch mv " +
		"  WHERE ROW(mv.trustgroup, mv.vouchee) = ROW($1, $2) " +
		"  AND mv.positive " +
		"  GROUP BY mv.vouchor " +
		") as for_me_vouches on (m.ident = for_me_vouches.member) " +
		"LEFT OUTER JOIN ( " +
		"  SELECT 'by_me' AS dir, mv.vouchee AS member, COUNT(*) AS num " +
		"  FROM member_vouch mv " +
		"  WHERE ROW(mv.trustgroup, mv.vouchor) = ROW($1, $2) " +
		"  AND mv.positive " +
		"  GROUP BY mv.vouchee " +
		") as by_me_vouches on (m.ident = by_me_vouches.member) " +
		"WHERE grp.ident = $1 " +
		"AND me.email = mt.email "

	if inclhidden {
		if nominated {
			q += "AND ms.ident = 'nominated' "
		}
	} else {
		if nominated {
			q += "AND (NOT ms.hidden OR ms.ident = 'nominated') "
		} else {
			q += "AND NOT ms.hidden "
		}
	}

	if search == "" {
		if max != 0 {
			q += ord + " LIMIT $4 OFFSET $3"
			rows, err = pf.DB.Query(q, grpn, username, offset, max)
		} else {
			q += ord
			rows, err = pf.DB.Query(q, grpn, username)
		}
	} else {
		if exact {
			q += "AND (m.ident ~* $3) " +
				ord

		} else {
			q += "AND (m.ident ~* $3 " +
				"OR m.descr ~* $3 " +
				"OR m.affiliation ~* $3) " +
				ord
		}

		if max != 0 {
			q += " LIMIT $5 OFFSET $4"
			rows, err = pf.DB.Query(q, grpn, username, search, offset, max)
		} else {
			rows, err = pf.DB.Query(q, grpn, username, search)
		}
	}

	if err != nil {
		pf.Log("Query failed: " + err.Error())
		return
	}

	defer rows.Close()

	for rows.Next() {
		var fullname string
		var username string
		var affiliation string
		var groupadmin bool
		var groupstate string
		var email string
		var pgpkey_id string
		var activity string
		var tel string
		var sms string
		var airport string

		member := NewTriGroupMember().(*TriGroupMemberS)

		err = rows.Scan(&username,
			&fullname,
			&affiliation,
			&groupadmin,
			&groupstate,
			&email,
			&pgpkey_id,
			&activity,
			&tel,
			&sms,
			&airport,
			&member.VouchesFor,
			&member.VouchesForMe,
			&member.VouchesBy,
			&member.VouchesByMe)
		if err != nil {
			pf.Log("Error listing members: " + err.Error())
			return nil, err
		}

		member.Set(grpn, username, fullname, affiliation, groupadmin, groupstate, email, pgpkey_id, activity, sms, tel, airport)
		members = append(members, member)
	}

	return members, nil
}

func (grp *TriGroupS) Add_default_attestations(ctx pf.PfCtx) (err error) {
	att := make(map[string]string)
	att["met"] = "I have met them in person more than once"
	att["trust"] = "I trust them to take action"
	att["fate"] = "I will share membership fate with them"

	for a, descr := range att {
		q := "INSERT INTO attestations " +
			"(ident, descr, trustgroup) " +
			"VALUES($1, $2, $3)"
		err = pf.DB.Exec(ctx,
			"Added default attestation $1 to group $3",
			1, q,
			a, descr, grp.GetGroupName())

		if err != nil {
			return
		}
	}

	return
}

func (grp *TriGroupS) Add_default_mailinglists(ctx pf.PfCtx) (err error) {
	err = grp.PfGroup.Add_default_mailinglists(ctx)
	if err != nil {
		return
	}

	mls := make(map[string]string)
	mls["vetting"] = "Vetting and Vouching"

	for lhs, descr := range mls {
		err = pf.Ml_addv(ctx, grp.PfGroup, lhs, descr, true, true, true)
		if err != nil {
			return
		}
	}

	return
}

func group_add(ctx pf.PfCtx, args []string) (err error) {
	var group_name string

	/* Make sure the name is mostly sane */
	group_name, err = pf.Chk_ident("Group Name", args[0])
	if err != nil {
		return
	}

	d_maxin := 180 * 24 * time.Hour
	i_maxin := d_maxin.Seconds()

	d_guard := 7 * 24 * time.Hour
	i_guard := d_guard.Seconds()

	grp := ctx.NewGroup().(TriGroup)
	exists := grp.Exists(group_name)
	if exists {
		err = errors.New("Group already exists")
		return
	}

	q := "INSERT INTO trustgroup " +
		"(ident, descr, shortname, min_invouch, pgp_required, " +
		" please_vouch, vouch_adminonly, min_outvouch, max_inactivity, can_time_out, " +
		" max_vouchdays, idle_guard, nom_enabled, target_invouch, has_wiki) " +
		"VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) "
	err = pf.DB.Exec(ctx,
		"Created group $1",
		1, q,
		group_name, group_name, group_name, 0, false,
		true, false, 0, i_maxin, false,
		0, i_guard, true, 0, false)

	if err != nil {
		err = errors.New("Group creation failed")
		return
	}

	err = ctx.SelectGroup(group_name, pf.PERM_SYS_ADMIN)
	if err != nil {
		err = errors.New("Group creation failed")
		return
	}

	/* Fetch our newly created group */
	tctx := TriGetCtx(ctx)
	grp = tctx.TriSelectedGroup()

	/* Select yourself */
	ctx.SelectMe()
	if err != nil {
		return
	}

	err = grp.Add_default_attestations(ctx)
	if err != nil {
		return
	}

	err = grp.Add_default_mailinglists(ctx)
	if err != nil {
		return
	}

	grp.Member_add(ctx)
	grp.Member_set_state(ctx, pf.GROUP_STATE_APPROVED)
	grp.Member_set_admin(ctx, true)

	/* All worked */
	ctx.OutLn("Creation of group %s complete", group_name)
	return
}

func group_member_nominate(ctx pf.PfCtx, args []string) (err error) {
	grp := ctx.SelectedGroup()
	return grp.Member_add(ctx)
}

func group_menu(ctx pf.PfCtx, menu *pf.PfMenu) {
	menu.Replace("add", group_add)

	m := []pf.PfMEntry{
		{"vouch", vouch_menu, 0, -1, nil, pf.PERM_USER, "Vouch Commands"},
		{"nominate", group_member_nominate, 2, 2, []string{"group", "username"}, pf.PERM_GROUP_MEMBER, "Nominate a member for a group"},
	}

	menu.Add(m...)
}
<commit_msg>Update to new ListGroupMembers() + GroupMember interface<commit_after>package trident

import (
	"errors"
	"time"
	"trident.li/keyval"
	pf "trident.li/pitchfork/lib"
)

type TriGroup interface {
	pf.PfGroup
	Add_default_attestations(ctx pf.PfCtx) (err error)
	GetVouch_adminonly() bool
	GetAttestations() (output []TriGroupAttestation, err error)
	GetAttestationsKVS() (kvs keyval.KeyVals, err error)
}

type TriGroupS struct {
	pf.PfGroup
	Please_vouch    bool   `label:"Please Vouch" pfset:"group_admin" hint:"Members must vouch before becoming active"`
	Vouch_adminonly bool   `label:"Vouch group admins only" pfset:"group_admin" hint:"Only adminstators may Vouvh"`
	Min_invouch     int    `label:"Minimum Inbound Vouches" pfset:"group_admin" hint:"Number of incoming vouches required to vett."`
	Min_outvouch    int    `label:"Minimum Outbound Vouches" pfset:"group_admin" hint:"Number of outgoing vouches required"`
	Target_invouch  int    `label:"Target Invouches" pfset:"group_admin"`
	Max_inactivity  string `label:"Maximum Inactivity" pfset:"group_admin"`
	Can_time_out    bool   `label:"Can Time Out" pfset:"group_admin"`
	Max_vouchdays   int    `label:"Maximum Vouch Days" pfset:"group_admin"`
	Idle_guard      string `label:"Idle Guard" pfset:"group_admin"`
	Nom_enabled     bool   `label:"Nominations Enabled" pfset:"group_admin"`
}

type TriGroupMember interface {
	pf.PfGroupMember
	GetVouchesFor() int
	GetVouchesBy() int
	GetVouchesForMe() int
	GetVouchesByMe() int
}

type TriGroupMemberS struct {
	pf.PfGroupMember
	VouchesFor   int
	VouchesBy    int
	VouchesForMe int
	VouchesByMe  int
}

func (o *TriGroupMemberS) GetVouchesFor() int {
	return o.VouchesFor
}

func (o *TriGroupMemberS) GetVouchesBy() int {
	return o.VouchesBy
}

func (o *TriGroupMemberS) GetVouchesForMe() int {
	return o.VouchesForMe
}

func (o *TriGroupMemberS) GetVouchesByMe() int {
	return o.VouchesByMe
}

/* Don't call directly, use ctx.NewGroup() */
func NewTriGroup() pf.PfGroup {
	return &TriGroupS{PfGroup: pf.NewPfGroup()}
}

func NewTriGroupMember() TriGroupMember {
	pfg := pf.NewPfGroupMember()
	return &TriGroupMemberS{PfGroupMember: pfg}
}

func (grp *TriGroupS) GetVouch_adminonly() bool {
	return grp.Vouch_adminonly
}

func (grp *TriGroupS) GetMembers(search string, username string, offset int, max int, nominated bool, inclhidden bool, exact bool) (members []pf.PfGroupMember, err error) {
	var rows *pf.Rows

	grpname := grp.GetGroupName()
	grpdesc := grp.GetGroupDesc()

	members = nil

	ord := "ORDER BY m.descr"

	q := "SELECT m.ident, " +
		"m.descr, " +
		"m.affiliation, " +
		"mt.admin, " +
		"mt.state, " +
		"mt.cansee, " +
		"me.email, " +
		"me.pgpkey_id, " +
		"  EXTRACT(day FROM now() - m.activity) as activity, " +
		"  tel_info, " +
		"  sms_info, " +
		"  m.airport, " +
		"  COALESCE(for_vouches.num, 0) AS vouches_for, " +
		"  COALESCE(for_me_vouches.num, 0) AS vouches_for_me, " +
		"  COALESCE(by_vouches.num, 0) AS vouches_by, " +
		"  COALESCE(by_me_vouches.num, 0) AS vouches_by_me " +
		"FROM member_trustgroup mt " +
		"INNER JOIN trustgroup grp ON (mt.trustgroup = grp.ident) " +
		"INNER JOIN member m ON (mt.member = m.ident) " +
		"INNER JOIN member_state ms ON (ms.ident = mt.state) " +
		"INNER JOIN member_email me ON (me.member = m.ident) " +
		"LEFT OUTER JOIN ( " +
		"  SELECT 'for' AS dir, mv.vouchee AS member, COUNT(*) AS num " +
		"  FROM member_vouch mv " +
		"  WHERE mv.trustgroup = $1 " +
		"  AND mv.positive " +
		"  GROUP BY mv.vouchee " +
		") as for_vouches on (m.ident = for_vouches.member) " +
		"LEFT OUTER JOIN ( " +
		"  SELECT 'by' AS dir, mv.vouchor AS member, COUNT(*) AS num " +
		"  FROM member_vouch mv " +
		"  WHERE mv.trustgroup = $1 " +
		"  AND mv.positive " +
		"  GROUP BY mv.vouchor " +
		") as by_vouches on (m.ident = by_vouches.member) " +
		"LEFT OUTER JOIN ( " +
		"  SELECT 'for_me' AS dir, mv.vouchor AS member, COUNT(*) AS num " +
		"  FROM member_vouch mv " +
		"  WHERE ROW(mv.trustgroup, mv.vouchee) = ROW($1, $2) " +
		"  AND mv.positive " +
		"  GROUP BY mv.vouchor " +
		") as for_me_vouches on (m.ident = for_me_vouches.member) " +
		"LEFT OUTER JOIN ( " +
		"  SELECT 'by_me' AS dir, mv.vouchee AS member, COUNT(*) AS num " +
		"  FROM member_vouch mv " +
		"  WHERE ROW(mv.trustgroup, mv.vouchor) = ROW($1, $2) " +
		"  AND mv.positive " +
		"  GROUP BY mv.vouchee " +
		") as by_me_vouches on (m.ident = by_me_vouches.member) " +
		"WHERE grp.ident = $1 " +
		"AND me.email = mt.email "

	if inclhidden {
		if nominated {
			q += "AND ms.ident = 'nominated' "
		}
	} else {
		if nominated {
			q += "AND (NOT ms.hidden OR ms.ident = 'nominated') "
		} else {
			q += "AND NOT ms.hidden "
		}
	}

	if search == "" {
		if max != 0 {
			q += ord + " LIMIT $4 OFFSET $3"
			rows, err = pf.DB.Query(q, grpname, username, offset, max)
		} else {
			q += ord
			rows, err = pf.DB.Query(q, grpname, username)
		}
	} else {
		if exact {
			q += "AND (m.ident ~* $3) " +
				ord

		} else {
			q += "AND (m.ident ~* $3 " +
				"OR m.descr ~* $3 " +
				"OR m.affiliation ~* $3) " +
				ord
		}

		if max != 0 {
			q += " LIMIT $5 OFFSET $4"
			rows, err = pf.DB.Query(q, grpname, username, search, offset, max)
		} else {
			rows, err = pf.DB.Query(q, grpname, username, search)
		}
	}

	if err != nil {
		pf.Log("Query failed: " + err.Error())
		return
	}

	defer rows.Close()

	for rows.Next() {
		var fullname string
		var username string
		var affiliation string
		var groupadmin bool
		var groupstate string
		var groupcansee bool
		var email string
		var pgpkey_id string
		var entered string
		var activity string
		var tel string
		var sms string
		var airport string

		member := NewTriGroupMember().(*TriGroupMemberS)

		err = rows.Scan(&username,
			&fullname,
			&affiliation,
			&groupadmin,
			&groupstate,
			&groupcansee,
			&email,
			&pgpkey_id,
			&entered,
			&activity,
			&tel,
			&sms,
			&airport,
			&member.VouchesFor,
			&member.VouchesForMe,
			&member.VouchesBy,
			&member.VouchesByMe)
		if err != nil {
			pf.Log("Error listing members: " + err.Error())
			return nil, err
		}

		member.Set(grpname, grpdesc, username, fullname, affiliation, groupadmin, groupstate, groupcansee, email, pgpkey_id, entered, activity, sms, tel, airport)
		members = append(members, member)
	}

	return members, nil
}

func (grp *TriGroupS) Add_default_attestations(ctx pf.PfCtx) (err error) {
	att := make(map[string]string)
	att["met"] = "I have met them in person more than once"
	att["trust"] = "I trust them to take action"
	att["fate"] = "I will share membership fate with them"

	for a, descr := range att {
		q := "INSERT INTO attestations " +
			"(ident, descr, trustgroup) " +
			"VALUES($1, $2, $3)"
		err = pf.DB.Exec(ctx,
			"Added default attestation $1 to group $3",
			1, q,
			a, descr, grp.GetGroupName())

		if err != nil {
			return
		}
	}

	return
}

func (grp *TriGroupS) Add_default_mailinglists(ctx pf.PfCtx) (err error) {
	err = grp.PfGroup.Add_default_mailinglists(ctx)
	if err != nil {
		return
	}

	mls := make(map[string]string)
	mls["vetting"] = "Vetting and Vouching"

	for lhs, descr := range mls {
		err = pf.Ml_addv(ctx, grp.PfGroup, lhs, descr, true, true, true)
		if err != nil {
			return
		}
	}

	return
}

func group_add(ctx pf.PfCtx, args []string) (err error) {
	var group_name string

	/* Make sure the name is mostly sane */
	group_name, err = pf.Chk_ident("Group Name", args[0])
	if err != nil {
		return
	}

	d_maxin := 180 * 24 * time.Hour
	i_maxin := d_maxin.Seconds()

	d_guard := 7 * 24 * time.Hour
	i_guard := d_guard.Seconds()

	grp := ctx.NewGroup().(TriGroup)
	exists := grp.Exists(group_name)
	if exists {
		err = errors.New("Group already exists")
		return
	}

	q := "INSERT INTO trustgroup " +
		"(ident, descr, shortname, min_invouch, pgp_required, " +
		" please_vouch, vouch_adminonly, min_outvouch, max_inactivity, can_time_out, " +
		" max_vouchdays, idle_guard, nom_enabled, target_invouch, has_wiki) " +
		"VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) "
	err = pf.DB.Exec(ctx,
		"Created group $1",
		1, q,
		group_name, group_name, group_name, 0, false,
		true, false, 0, i_maxin, false,
		0, i_guard, true, 0, false)

	if err != nil {
		err = errors.New("Group creation failed")
		return
	}

	err = ctx.SelectGroup(group_name, pf.PERM_SYS_ADMIN)
	if err != nil {
		err = errors.New("Group creation failed")
		return
	}

	/* Fetch our newly created group */
	tctx := TriGetCtx(ctx)
	grp = tctx.TriSelectedGroup()

	/* Select yourself */
	ctx.SelectMe()
	if err != nil {
		return
	}

	err = grp.Add_default_attestations(ctx)
	if err != nil {
		return
	}

	err = grp.Add_default_mailinglists(ctx)
	if err != nil {
		return
	}

	grp.Member_add(ctx)
	grp.Member_set_state(ctx, pf.GROUP_STATE_APPROVED)
	grp.Member_set_admin(ctx, true)

	/* All worked */
	ctx.OutLn("Creation of group %s complete", group_name)
	return
}

func group_member_nominate(ctx pf.PfCtx, args []string) (err error) {
	grp := ctx.SelectedGroup()
	return grp.Member_add(ctx)
}

func group_menu(ctx pf.PfCtx, menu *pf.PfMenu) {
	menu.Replace("add", group_add)

	m := []pf.PfMEntry{
		{"vouch", vouch_menu, 0, -1, nil, pf.PERM_USER, "Vouch Commands"},
		{"nominate", group_member_nominate, 2, 2, []string{"group", "username"}, pf.PERM_GROUP_MEMBER, "Nominate a member for a group"},
	}

	menu.Add(m...)
}
<|endoftext|>


<commit_before>package jwthelper

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"sync"

	"github.com/dgrijalva/jwt-go"
	"github.com/dgrijalva/jwt-go/request"
	"github.com/northbright/pathhelper"
)

// Key struct consists of algorithm, signning key and verifying key.
type Key struct {
	Method    jwt.SigningMethod // jwt.SigningMethod
	SignKey   interface{}       // Signing key. HMAC: []byte, RSA / RSAPSS: *crypto/rsa.PrivateKey, ECDSA: *crypto/ecdsa.PrivateKey.
	VerifyKey interface{}       // Verifying key. HMAC: []byte, RSA / RSAPSS: *crypto/rsa.PublicKey, ECDSA: *crypto/ecdsa.PublicKey.
}

// KeyManager manages the keys by using kid(key id).
type KeyManager struct {
	Keys         map[string]*Key // Key map. Key: kid(key id), Value: Key Struct
	sync.RWMutex                 // Access map concurrently.
}

const (
	availableAlgs string = "Available algs: HS256,HS384,HS512,RS256,RS384,RS512,PS256,PS384,PS512,ES256,ES384,ES512"
)

var (
	km = KeyManager{Keys: make(map[string]*Key)} // Internal key manager.
)

// ReadKey reads key bytes from the key file.
func ReadKey(keyFile string) (key []byte, err error) {
	// Make Abs key file path with current executable path if KeyFilePath is relative.
	p := ""
	if p, err = pathhelper.GetAbsPath(keyFile); err != nil {
		return nil, err
	}

	buf := []byte{}
	if buf, err = ioutil.ReadFile(p); err != nil {
		return nil, err
	}

	return buf, nil
}

// SetKey sets the kid - Key pair.
//
//   Params:
//       kid: Key id. It should be unique.
//       key: Key struct.
func SetKey(kid string, key *Key) {
	km.Lock()
	km.Keys[kid] = key
	km.Unlock()
}

// GetKey return the key struct by given kid.
func GetKey(kid string) (k *Key, err error) {
	km.RLock()
	k, ok := km.Keys[kid]
	km.RUnlock()

	if !ok {
		return nil, errors.New("No such key id.")
	}

	return k, nil
}

// DeleteKey deletes the specified entry from the key map.
func DeleteKey(kid string) (err error) {
	if _, err := GetKey(kid); err != nil {
		return err
	}

	km.Lock()
	delete(km.Keys, kid)
	km.Unlock()

	return nil
}

// SetKeyFromFile reads the key files and stores the unique kid - Key information pair.
//
//   Params:
//       kid: Key id(unique).
//       alg: JWT alg.
//       signKeyFile: Signing key file.
//       verifyKeyFile: Verifying key file.
//   Return:
//       err: error.
//   Notes:
//       1. Current Available JWT "alg": HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512.
//       2. HMAC using SHA-XXX is a symmetric key algorithm. It just read signKeyFile as secret key(verifyKeyFile is ignored).
//       3. How to Generate Keys for JWT algs:
//          https://github.com/northbright/Notes/blob/master/jwt/generate_keys_for_jwt_alg.md
func SetKeyFromFile(kid, alg, signKeyFile, verifyKeyFile string) (err error) {
	key := &Key{}

	m := jwt.GetSigningMethod(alg)
	if m == nil {
		msg := fmt.Sprintf("Incorrect alg: %s. %s", alg, availableAlgs)
		return errors.New(msg)
	}

	// Set Signing Method
	key.Method = m

	switch alg {
	case "HS256", "HS384", "HS512":
		if key.SignKey, err = ReadKey(signKeyFile); err != nil {
			return err
		}
		key.VerifyKey = key.SignKey

	case "RS256", "RS384", "RS512", "PS256", "PS384", "PS512":
		buf := []byte{}
		if buf, err = ReadKey(signKeyFile); err != nil {
			return err
		}

		if key.SignKey, err = jwt.ParseRSAPrivateKeyFromPEM(buf); err != nil {
			return err
		}

		if buf, err = ReadKey(verifyKeyFile); err != nil {
			return err
		}

		if key.VerifyKey, err = jwt.ParseRSAPublicKeyFromPEM(buf); err != nil {
			return err
		}

	case "ES256", "ES384", "ES512":
		buf := []byte{}
		if buf, err = ReadKey(signKeyFile); err != nil {
			return err
		}

		if key.SignKey, err = jwt.ParseECPrivateKeyFromPEM(buf); err != nil {
			return err
		}

		if buf, err = ReadKey(verifyKeyFile); err != nil {
			return err
		}

		if key.VerifyKey, err = jwt.ParseECPublicKeyFromPEM(buf); err != nil {
			return err
		}
	default:
		msg := fmt.Sprintf("Incorrect alg: %s. %s", alg, availableAlgs)
		return errors.New(msg)
	}

	SetKey(kid, key)
	return nil
}

// CreateTokenString creates a new JWT token string.
//
//   Params:
//       kid: Key id.
//       claims: map[string]interface{} to fill the jwt.Token[Claims].
//   Return:
//       tokenString: new created JWT token string.
//       err: error.
func CreateTokenString(kid string, claims map[string]interface{}) (tokenString string, err error) {
	var k *Key

	if k, err = GetKey(kid); err != nil {
		return "", err
	}

	t := jwt.NewWithClaims(k.Method, jwt.MapClaims(claims))
	t.Header["kid"] = kid
	return t.SignedString(k.SignKey)
}

// jwt-go's KeyFunc type:
//
// type Keyfunc func(*Token) (interface{}, error)
func keyFunc(token *jwt.Token) (interface{}, error) {
	kid := ""
	str := ""
	ok := false

	if str, ok = token.Header["kid"].(string); !ok {
		msg := fmt.Sprintf("token.Header[\"kid\"]'s type is %T, but not string.", token.Header["kid"])
		return nil, errors.New(msg)
	}

	kid = str
	key, err := GetKey(kid)
	if err != nil {
		return nil, err
	}

	// Check signing method
	if token.Method.Alg() != key.Method.Alg() {
		return nil, errors.New("Signing Method Error.")
	}

	return key.VerifyKey, nil
}

// Parse parses and validates the input token string.
//
//   Params:
//       tokenString: input JWT token string.
//   Return:
//       kid: Key id.
//       claims: map[string]interface{} to fill the jwt.Token[Claims].
//       valid: token is valid or not.
//       err: error.
func Parse(tokenString string) (kid string, claims map[string]interface{}, valid bool, err error) {
	t, err := jwt.Parse(tokenString, keyFunc)
	if err != nil {
		return "", nil, false, err
	}

	return t.Header["kid"].(string), t.Claims.(jwt.MapClaims), t.Valid, nil
}

// ParseFromRequest parses and validates the input token string in an http.Request. It's a wrapper of jwt.ParseFromRequest().
//
//   Params:
//       r: http.Request may contain jwt token.
//       extractor: Interface for extracting a token from an HTTP request.
//                  See https://godoc.org/github.com/dgrijalva/jwt-go/request#Extractor
//   Return:
//       kid: Key id.
//       claims: map[string]interface{} to fill the jwt.Token[Claims].
//       valid: token is valid or not.
//       err: error.
func ParseFromRequest(r *http.Request, e request.Extractor) (kid string, claims map[string]interface{}, valid bool, err error) {
	t, err := request.ParseFromRequest(r, e, keyFunc)
	if err != nil {
		return "", nil, false, err
	}

	return t.Header["kid"].(string), t.Claims.(jwt.MapClaims), t.Valid, nil
}
<commit_msg>Replace errors.New() with fmt.Errorf().<commit_after>package jwthelper

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"sync"

	"github.com/dgrijalva/jwt-go"
	"github.com/dgrijalva/jwt-go/request"
	"github.com/northbright/pathhelper"
)

// Key struct consists of algorithm, signning key and verifying key.
type Key struct {
	Method    jwt.SigningMethod // jwt.SigningMethod
	SignKey   interface{}       // Signing key. HMAC: []byte, RSA / RSAPSS: *crypto/rsa.PrivateKey, ECDSA: *crypto/ecdsa.PrivateKey.
	VerifyKey interface{}       // Verifying key. HMAC: []byte, RSA / RSAPSS: *crypto/rsa.PublicKey, ECDSA: *crypto/ecdsa.PublicKey.
}

// KeyManager manages the keys by using kid(key id).
type KeyManager struct {
	Keys         map[string]*Key // Key map. Key: kid(key id), Value: Key Struct
	sync.RWMutex                 // Access map concurrently.
}

const (
	availableAlgs string = "Available algs: HS256,HS384,HS512,RS256,RS384,RS512,PS256,PS384,PS512,ES256,ES384,ES512"
)

var (
	km = KeyManager{Keys: make(map[string]*Key)} // Internal key manager.
)

// ReadKey reads key bytes from the key file.
func ReadKey(keyFile string) (key []byte, err error) {
	// Make Abs key file path with current executable path if KeyFilePath is relative.
	p := ""
	if p, err = pathhelper.GetAbsPath(keyFile); err != nil {
		return nil, err
	}

	buf := []byte{}
	if buf, err = ioutil.ReadFile(p); err != nil {
		return nil, err
	}

	return buf, nil
}

// SetKey sets the kid - Key pair.
//
//   Params:
//       kid: Key id. It should be unique.
//       key: Key struct.
func SetKey(kid string, key *Key) {
	km.Lock()
	km.Keys[kid] = key
	km.Unlock()
}

// GetKey return the key struct by given kid.
func GetKey(kid string) (k *Key, err error) {
	km.RLock()
	k, ok := km.Keys[kid]
	km.RUnlock()

	if !ok {
		return nil, fmt.Errorf("No such key id.")
	}

	return k, nil
}

// DeleteKey deletes the specified entry from the key map.
func DeleteKey(kid string) (err error) {
	if _, err := GetKey(kid); err != nil {
		return err
	}

	km.Lock()
	delete(km.Keys, kid)
	km.Unlock()

	return nil
}

// SetKeyFromFile reads the key files and stores the unique kid - Key information pair.
//
//   Params:
//       kid: Key id(unique).
//       alg: JWT alg.
//       signKeyFile: Signing key file.
//       verifyKeyFile: Verifying key file.
//   Return:
//       err: error.
//   Notes:
//       1. Current Available JWT "alg": HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512.
//       2. HMAC using SHA-XXX is a symmetric key algorithm. It just read signKeyFile as secret key(verifyKeyFile is ignored).
//       3. How to Generate Keys for JWT algs:
//          https://github.com/northbright/Notes/blob/master/jwt/generate_keys_for_jwt_alg.md
func SetKeyFromFile(kid, alg, signKeyFile, verifyKeyFile string) (err error) {
	key := &Key{}

	m := jwt.GetSigningMethod(alg)
	if m == nil {
		return fmt.Errorf("Incorrect alg: %s. %s", alg, availableAlgs)
	}

	// Set Signing Method
	key.Method = m

	switch alg {
	case "HS256", "HS384", "HS512":
		if key.SignKey, err = ReadKey(signKeyFile); err != nil {
			return err
		}
		key.VerifyKey = key.SignKey

	case "RS256", "RS384", "RS512", "PS256", "PS384", "PS512":
		buf := []byte{}
		if buf, err = ReadKey(signKeyFile); err != nil {
			return err
		}

		if key.SignKey, err = jwt.ParseRSAPrivateKeyFromPEM(buf); err != nil {
			return err
		}

		if buf, err = ReadKey(verifyKeyFile); err != nil {
			return err
		}

		if key.VerifyKey, err = jwt.ParseRSAPublicKeyFromPEM(buf); err != nil {
			return err
		}

	case "ES256", "ES384", "ES512":
		buf := []byte{}
		if buf, err = ReadKey(signKeyFile); err != nil {
			return err
		}

		if key.SignKey, err = jwt.ParseECPrivateKeyFromPEM(buf); err != nil {
			return err
		}

		if buf, err = ReadKey(verifyKeyFile); err != nil {
			return err
		}

		if key.VerifyKey, err = jwt.ParseECPublicKeyFromPEM(buf); err != nil {
			return err
		}
	default:
		return fmt.Errorf("Incorrect alg: %s. %s", alg, availableAlgs)
	}

	SetKey(kid, key)
	return nil
}

// CreateTokenString creates a new JWT token string.
//
//   Params:
//       kid: Key id.
//       claims: map[string]interface{} to fill the jwt.Token[Claims].
//   Return:
//       tokenString: new created JWT token string.
//       err: error.
func CreateTokenString(kid string, claims map[string]interface{}) (tokenString string, err error) {
	var k *Key

	if k, err = GetKey(kid); err != nil {
		return "", err
	}

	t := jwt.NewWithClaims(k.Method, jwt.MapClaims(claims))
	t.Header["kid"] = kid
	return t.SignedString(k.SignKey)
}

// jwt-go's KeyFunc type:
//
// type Keyfunc func(*Token) (interface{}, error)
func keyFunc(token *jwt.Token) (interface{}, error) {
	kid := ""
	str := ""
	ok := false

	if str, ok = token.Header["kid"].(string); !ok {
		msg := fmt.Sprintf("token.Header[\"kid\"]'s type is %T, but not string.", token.Header["kid"])
		return nil, fmt.Errorf(msg)
	}

	kid = str
	key, err := GetKey(kid)
	if err != nil {
		return nil, err
	}

	// Check signing method
	if token.Method.Alg() != key.Method.Alg() {
		return nil, fmt.Errorf("Signing Method Error.")
	}

	return key.VerifyKey, nil
}

// Parse parses and validates the input token string.
//
//   Params:
//       tokenString: input JWT token string.
//   Return:
//       kid: Key id.
//       claims: map[string]interface{} to fill the jwt.Token[Claims].
//       valid: token is valid or not.
//       err: error.
func Parse(tokenString string) (kid string, claims map[string]interface{}, valid bool, err error) {
	t, err := jwt.Parse(tokenString, keyFunc)
	if err != nil {
		return "", nil, false, err
	}

	return t.Header["kid"].(string), t.Claims.(jwt.MapClaims), t.Valid, nil
}

// ParseFromRequest parses and validates the input token string in an http.Request. It's a wrapper of jwt.ParseFromRequest().
//
//   Params:
//       r: http.Request may contain jwt token.
//       extractor: Interface for extracting a token from an HTTP request.
//                  See https://godoc.org/github.com/dgrijalva/jwt-go/request#Extractor
//   Return:
//       kid: Key id.
//       claims: map[string]interface{} to fill the jwt.Token[Claims].
//       valid: token is valid or not.
//       err: error.
func ParseFromRequest(r *http.Request, e request.Extractor) (kid string, claims map[string]interface{}, valid bool, err error) {
	t, err := request.ParseFromRequest(r, e, keyFunc)
	if err != nil {
		return "", nil, false, err
	}

	return t.Header["kid"].(string), t.Claims.(jwt.MapClaims), t.Valid, nil
}
<|endoftext|>


<commit_before>// Package keys provides constants for all the keyboard inputs.
package keys

import "fmt"

// Key represents a VNC key press.
type Key uint32

//go:generate stringer -type=Key

// Keys is a slice of Key values.
type Keys []Key

var keymap = map[rune]Key{
	'-': Minus,
	'0': Digit0,
	'1': Digit1,
	'2': Digit2,
	'3': Digit3,
	'4': Digit4,
	'5': Digit5,
	'6': Digit6,
	'7': Digit7,
	'8': Digit8,
	'9': Digit9,
}

// IntToKeys returns Keys that represent the key presses required to type an int.
func IntToKeys(v int) Keys {
	k := Keys{}
	for _, c := range fmt.Sprintf("%d", v) {
		k = append(k, keymap[c])
	}
	return k
}

// Latin 1 (byte 3 = 0)
// ISO/IEC 8859-1 = Unicode U+0020..U+00FF
const (
	Space   Key = iota + 0x0020
	Exclaim     // exclamation mark
	QuoteDbl
	NumberSign
	Dollar
	Percent
	Ampersand
	Apostrophe
	ParenLeft
	ParenRight
	Asterisk
	Plus
	Comma
	Minus
	Period
	Slash
	Digit0
	Digit1
	Digit2
	Digit3
	Digit4
	Digit5
	Digit6
	Digit7
	Digit8
	Digit9
	Colon
	Semicolon
	Less
	Equal
	Greater
	Question
	At
	A
	B
	C
	D
	E
	F
	G
	H
	I
	J
	K
	L
	M
	N
	O
	P
	Q
	R
	S
	T
	U
	V
	X
	Y
	Z
	BracketLeft
	Backslash
	BracketRight
	AsciiCircum
	Underscore
	Grave
	SmallA
	SmallB
	SmallC
	SmallD
	SmallE
	SmallF
	SmallG
	SmallH
	SmallI
	SmallJ
	SmallK
	SmallL
	SmallM
	SmallN
	SmallO
	SmallP
	SmallQ
	SmallR
	SmallS
	SmallT
	SmallU
	SmallV
	SmallX
	SmallY
	SmallZ
	BraceLeft
	Bar
	BraceRight
	AsciiTilde
)
const (
	BackSpace Key = iota + 0xff08
	Tab
	Linefeed
	Clear
	_
	Return
)
const (
	Pause Key = iota + 0xff13
	ScrollLock
	SysReq
	Escape Key = 0xff1b
	Delete Key = 0xffff
)
const ( // Cursor control & motion.
	Home Key = iota + 0xff50
	Left
	Up
	Right
	Down
	PageUp
	PageDown
	End
	Begin
)
const ( // Misc functions.
	Select Key = 0xff60
	Print
	Execute
	Insert
	Undo
	Redo
	Menu
	Find
	Cancel
	Help
	Break
	ModeSwitch Key = 0xff7e
	NumLock    Key = 0xff7f
)
const ( // Keypad functions.
	KeypadSpace Key = 0xff80
	KeypadTab   Key = 0xff89
	KeypadEnter Key = 0xff8d
)
const ( // Keypad functions cont.
	KeypadF1 Key = iota + 0xff91
	KeypadF2
	KeypadF3
	KeypadF4
	KeypadHome
	KeypadLeft
	KeypadUp
	KeypadRight
	KeypadDown
	KeypadPrior
	KeypadPageUp
	KeypadNext
	KeypadPageDown
	KeypadEnd
	KeypadBegin
	KeypadInsert
	KeypadDelete
	KeypadMultiply
	KeypadAdd
	KeypadSeparator
	KeypadSubtract
	KeypadDecimal
	KeypadDivide
	Keypad0
	Keypad1
	Keypad2
	Keypad3
	Keypad4
	Keypad5
	Keypad6
	Keypad7
	Keypad8
	Keypad9
	KeypadEqual Key = 0xffbd
)
const (
	F1 Key = iota + 0xffbe
	F2
	F3
	F4
	F5
	F6
	F7
	F8
	F9
	F10
	F11
	F12
)
const (
	ShiftLeft Key = iota + 0xffe1
	ShiftRight
	ControlLeft
	ControlRight
	CapsLock
	ShiftLock
	MetaLeft
	MetaRight
	AltLeft
	AltRight
	SuperLeft
	SuperRight
	HyperLeft
	HyperRight
)
<commit_msg>Added missing W back into key constants file<commit_after>// Package keys provides constants for all the keyboard inputs.
package keys

import "fmt"

// Key represents a VNC key press.
type Key uint32

//go:generate stringer -type=Key

// Keys is a slice of Key values.
type Keys []Key

var keymap = map[rune]Key{
	'-': Minus,
	'0': Digit0,
	'1': Digit1,
	'2': Digit2,
	'3': Digit3,
	'4': Digit4,
	'5': Digit5,
	'6': Digit6,
	'7': Digit7,
	'8': Digit8,
	'9': Digit9,
}

// IntToKeys returns Keys that represent the key presses required to type an int.
func IntToKeys(v int) Keys {
	k := Keys{}
	for _, c := range fmt.Sprintf("%d", v) {
		k = append(k, keymap[c])
	}
	return k
}

// Latin 1 (byte 3 = 0)
// ISO/IEC 8859-1 = Unicode U+0020..U+00FF
const (
	Space   Key = iota + 0x0020
	Exclaim     // exclamation mark
	QuoteDbl
	NumberSign
	Dollar
	Percent
	Ampersand
	Apostrophe
	ParenLeft
	ParenRight
	Asterisk
	Plus
	Comma
	Minus
	Period
	Slash
	Digit0
	Digit1
	Digit2
	Digit3
	Digit4
	Digit5
	Digit6
	Digit7
	Digit8
	Digit9
	Colon
	Semicolon
	Less
	Equal
	Greater
	Question
	At
	A
	B
	C
	D
	E
	F
	G
	H
	I
	J
	K
	L
	M
	N
	O
	P
	Q
	R
	S
	T
	U
	V
	W
	X
	Y
	Z
	BracketLeft
	Backslash
	BracketRight
	AsciiCircum
	Underscore
	Grave
	SmallA
	SmallB
	SmallC
	SmallD
	SmallE
	SmallF
	SmallG
	SmallH
	SmallI
	SmallJ
	SmallK
	SmallL
	SmallM
	SmallN
	SmallO
	SmallP
	SmallQ
	SmallR
	SmallS
	SmallT
	SmallU
	SmallV
	SmallW
	SmallX
	SmallY
	SmallZ
	BraceLeft
	Bar
	BraceRight
	AsciiTilde
)
const (
	BackSpace Key = iota + 0xff08
	Tab
	Linefeed
	Clear
	_
	Return
)
const (
	Pause Key = iota + 0xff13
	ScrollLock
	SysReq
	Escape Key = 0xff1b
	Delete Key = 0xffff
)
const ( // Cursor control & motion.
	Home Key = iota + 0xff50
	Left
	Up
	Right
	Down
	PageUp
	PageDown
	End
	Begin
)
const ( // Misc functions.
	Select Key = 0xff60
	Print
	Execute
	Insert
	Undo
	Redo
	Menu
	Find
	Cancel
	Help
	Break
	ModeSwitch Key = 0xff7e
	NumLock    Key = 0xff7f
)
const ( // Keypad functions.
	KeypadSpace Key = 0xff80
	KeypadTab   Key = 0xff89
	KeypadEnter Key = 0xff8d
)
const ( // Keypad functions cont.
	KeypadF1 Key = iota + 0xff91
	KeypadF2
	KeypadF3
	KeypadF4
	KeypadHome
	KeypadLeft
	KeypadUp
	KeypadRight
	KeypadDown
	KeypadPrior
	KeypadPageUp
	KeypadNext
	KeypadPageDown
	KeypadEnd
	KeypadBegin
	KeypadInsert
	KeypadDelete
	KeypadMultiply
	KeypadAdd
	KeypadSeparator
	KeypadSubtract
	KeypadDecimal
	KeypadDivide
	Keypad0
	Keypad1
	Keypad2
	Keypad3
	Keypad4
	Keypad5
	Keypad6
	Keypad7
	Keypad8
	Keypad9
	KeypadEqual Key = 0xffbd
)
const (
	F1 Key = iota + 0xffbe
	F2
	F3
	F4
	F5
	F6
	F7
	F8
	F9
	F10
	F11
	F12
)
const (
	ShiftLeft Key = iota + 0xffe1
	ShiftRight
	ControlLeft
	ControlRight
	CapsLock
	ShiftLock
	MetaLeft
	MetaRight
	AltLeft
	AltRight
	SuperLeft
	SuperRight
	HyperLeft
	HyperRight
)
<|endoftext|>


<commit_before>package lexer

import (
  "github.com/Southern/scanner"
  "regexp"
  "strings"
)

func init() {
  Languages = map[string]*Language{
    "Javascript": &Language{
      Extensions: []string{"js"},
      Map: append([]scanner.Definition{
        // Single line comments
        regex["comments"]["oneline"],

        // Multi-line comments
        regex["comments"]["multiline"],

        // Double quote strings
        regex["string"]["double"],

        // Single quote strings
        regex["string"]["single"],

        // Operators
        scanner.Definition{regexp.MustCompile("^(\\+{1,2}|-{1,2}|[=%])"), "OPERATOR"},

        // Restricted words
        scanner.Definition{regexp.MustCompile(
          strings.Join([]string{
            "^(",
            strings.Join([]string{
              "Object",
              "[fF]unction",
              "Boolean",
              "Error",
              "EvalError",
              "InternalError",
              "RangeError",
              "ReferenceError",
              "SyntaxError",
              "TypeError",
              "URIError",
              "Number",
              "Math",
              "Date",
              "String",
              "RegExp",
              "Array",
              "U?Int8Array",
              "UInt8ClampedArray",
              "U?Int16Array",
              "(U?Int|Float)32Array",
              "Float64Array",
              "ArrayBuffer",
              "DataView",
              "JSON",
              "Infinity",
              "NaN",
              "undefined",
              "null",
              "__proto__",
              "prototype",
              "constructor",
              "new",
              "true",
              "false",
              "for",
              "while",
              "(set|clear)Timeout",
              "(set|clear)Interval",
              "if",
              "else",
            }, "|"),
            ")",
          }, ""),
        ), "IDENT"},
      }, scanner.Map()...),
      Modify: [][][]string{
        [][]string{
          []string{"CHAR", "{"},
          []string{"BLOCKSTART"},
        },
        [][]string{
          []string{"CHAR", "}"},
          []string{"BLOCKEND"},
        },
        [][]string{
          []string{"CHAR", "("},
          []string{"ARGSTART"},
        },
        [][]string{
          []string{"CHAR", ")"},
          []string{"ARGEND"},
        },
        [][]string{
          []string{"CHAR", ";"},
          []string{"END"},
        },
      },
    },

    "Go": &Language{
      Extensions: []string{"go"},
      Map: append([]scanner.Definition{
        // Single line comments
        regex["comments"]["oneline"],

        // Multi-line comments
        regex["comments"]["multiline"],

        // Double quote strings
        regex["string"]["double"],

        // Operators
        scanner.Definition{regexp.MustCompile("^(\\+{1,2}|-{1,2}|[=%])"), "OPERATOR"},

        // Restricted words
        scanner.Definition{regexp.MustCompile(
          strings.Join([]string{
            "^(",
            strings.Join([]string{
              "(Complex|Float|Integer)?Type",
              "Type1",
              "bool",
              "byte",
              "complex(64|128)",
              "error",
              "float(32|64)",
              "string",
              "u?int(8|16|32|64)?",
              "uintptr",
              "true",
              "false",
              "iota",
              "func",
              "type",
              "struct",
            }, "|"),
            ")",
          }, ""),
        ), "IDENT"},
      }, scanner.Map()...),
      Modify: [][][]string{
        [][]string{
          []string{"CHAR", "{"},
          []string{"BLOCKSTART"},
        },
        [][]string{
          []string{"CHAR", "}"},
          []string{"BLOCKEND"},
        },
        [][]string{
          []string{"CHAR", "("},
          []string{"ARGSTART"},
        },
        [][]string{
          []string{"CHAR", ")"},
          []string{"ARGEND"},
        },
      },
    },
  }

  Languages["Node"] = Languages["Javascript"]
  Languages["Node"].Map = append([]scanner.Definition{
    // Restricted Node words
    scanner.Definition{regexp.MustCompile(
      strings.Join([]string{
        "^(",
        strings.Join([]string{
          "module",
          "exports",
          "require",
          "global",
          "process",
          "console",
          "__dirname",
          "__filename",
        }, "|"),
        ")",
      }, ""),
    ), "IDENT"},
  }, Languages["Node"].Map...)
}
<commit_msg>Add more Go restricted words<commit_after>package lexer

import (
  "github.com/Southern/scanner"
  "regexp"
  "strings"
)

func init() {
  Languages = map[string]*Language{
    "Javascript": &Language{
      Extensions: []string{"js"},
      Map: append([]scanner.Definition{
        // Single line comments
        regex["comments"]["oneline"],

        // Multi-line comments
        regex["comments"]["multiline"],

        // Double quote strings
        regex["string"]["double"],

        // Single quote strings
        regex["string"]["single"],

        // Operators
        scanner.Definition{regexp.MustCompile("^(\\+{1,2}|-{1,2}|[=%])"), "OPERATOR"},

        // Restricted words
        scanner.Definition{regexp.MustCompile(
          strings.Join([]string{
            "^(",
            strings.Join([]string{
              "Object",
              "[fF]unction",
              "Boolean",
              "Error",
              "EvalError",
              "InternalError",
              "RangeError",
              "ReferenceError",
              "SyntaxError",
              "TypeError",
              "URIError",
              "Number",
              "Math",
              "Date",
              "String",
              "RegExp",
              "Array",
              "U?Int8Array",
              "UInt8ClampedArray",
              "U?Int16Array",
              "(U?Int|Float)32Array",
              "Float64Array",
              "ArrayBuffer",
              "DataView",
              "JSON",
              "Infinity",
              "NaN",
              "undefined",
              "null",
              "__proto__",
              "prototype",
              "constructor",
              "new",
              "true",
              "false",
              "for",
              "while",
              "(set|clear)Timeout",
              "(set|clear)Interval",
              "if",
              "else",
            }, "|"),
            ")",
          }, ""),
        ), "IDENT"},
      }, scanner.Map()...),
      Modify: [][][]string{
        [][]string{
          []string{"CHAR", "{"},
          []string{"BLOCKSTART"},
        },
        [][]string{
          []string{"CHAR", "}"},
          []string{"BLOCKEND"},
        },
        [][]string{
          []string{"CHAR", "("},
          []string{"ARGSTART"},
        },
        [][]string{
          []string{"CHAR", ")"},
          []string{"ARGEND"},
        },
        [][]string{
          []string{"CHAR", ";"},
          []string{"END"},
        },
      },
    },

    "Go": &Language{
      Extensions: []string{"go"},
      Map: append([]scanner.Definition{
        // Single line comments
        regex["comments"]["oneline"],

        // Multi-line comments
        regex["comments"]["multiline"],

        // Double quote strings
        regex["string"]["double"],

        // Operators
        scanner.Definition{regexp.MustCompile("^(\\+{1,2}|-{1,2}|[=%])"), "OPERATOR"},

        // Restricted words
        scanner.Definition{regexp.MustCompile(
          strings.Join([]string{
            "^(",
            strings.Join([]string{
              "(Complex|Float|Integer)?Type",
              "Type1",
              "bool",
              "byte",
              "complex(64|128)",
              "error",
              "float(32|64)",
              "string",
              "u?int(8|16|32|64)?",
              "uintptr",
              "true",
              "false",
              "iota",
              "func",
              "type",
              "struct",
              "chan",
              "for",
              "if",
              "else",
              "map",
            }, "|"),
            ")",
          }, ""),
        ), "IDENT"},
      }, scanner.Map()...),
      Modify: [][][]string{
        [][]string{
          []string{"CHAR", "{"},
          []string{"BLOCKSTART"},
        },
        [][]string{
          []string{"CHAR", "}"},
          []string{"BLOCKEND"},
        },
        [][]string{
          []string{"CHAR", "("},
          []string{"ARGSTART"},
        },
        [][]string{
          []string{"CHAR", ")"},
          []string{"ARGEND"},
        },
      },
    },
  }

  Languages["Node"] = Languages["Javascript"]
  Languages["Node"].Map = append([]scanner.Definition{
    // Restricted Node words
    scanner.Definition{regexp.MustCompile(
      strings.Join([]string{
        "^(",
        strings.Join([]string{
          "module",
          "exports",
          "require",
          "global",
          "process",
          "console",
          "__dirname",
          "__filename",
        }, "|"),
        ")",
      }, ""),
    ), "IDENT"},
  }, Languages["Node"].Map...)
}
<|endoftext|>


<commit_before>package lars

import (
	"log"
	"net/http"
	"testing"

	. "gopkg.in/go-playground/assert.v1"
)

// . "gopkg.in/go-playground/assert.v1"

// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//

var basicHandler = func(Context) {

}

func TestLARS(t *testing.T) {
	l := New()

	l.Get("/", func(c Context) {
		c.Response().Write([]byte("home"))
	})

	code, body := request(GET, "/", l)
	Equal(t, code, http.StatusOK)
	Equal(t, body, "home")
}

func TestLARSStatic(t *testing.T) {
	l := New()
	path := "/github.com/go-experimental/:id"
	l.Get(path, basicHandler)
	code, body := request(GET, "/github.com/go-experimental/808w70", l)
	Equal(t, code, http.StatusOK)
	Equal(t, body, "")
}

func TestLARSParam(t *testing.T) {
	l := New()
	path := "/github.com/go-experimental/:id/"
	l.Get(path, func(c Context) {
		p, _ := c.Param("id")
		c.Response().Write([]byte(p))
	})
	code, body := request(GET, "/github.com/go-experimental/808w70/", l)

	log.Println(code, body)

}
<commit_msg>Updates on LARS test<commit_after>package lars

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

	. "gopkg.in/go-playground/assert.v1"
)

// . "gopkg.in/go-playground/assert.v1"

// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//

var basicHandler = func(Context) {
}

func TestLARS(t *testing.T) {
	l := New()

	l.Get("/", func(c Context) {
		c.Response().Write([]byte("home"))
	})

	code, body := request(GET, "/", l)
	Equal(t, code, http.StatusOK)
	Equal(t, body, "home")
}

func TestLARSStatic(t *testing.T) {
	l := New()
	path := "/github.com/go-experimental/:id"
	l.Get(path, basicHandler)
	code, body := request(GET, "/github.com/go-experimental/808w70", l)
	Equal(t, code, http.StatusOK)
	Equal(t, body, "")
}

func TestLARSParam(t *testing.T) {
	l := New()
	path := "/github.com/go-experimental/:id/"
	l.Get(path, func(c Context) {
		p, _ := c.Param("id")
		c.Response().Write([]byte(p))
	})
	code, body := request(GET, "/github.com/go-experimental/808w70/", l)

	Equal(t, code, http.StatusOK)
	Equal(t, body, "808w70")
}

func TestLARSTwoParam(t *testing.T) {
	var p Params

	l := New()
	path := "/github.com/user/:id/:age/"
	l.Get(path, func(c Context) {
		p = c.Params()
	})

	code, _ := request(GET, "/github.com/user/808w70/67/", l)

	Equal(t, code, http.StatusOK)
	Equal(t, p[0].Value, "808w70")
	Equal(t, p[1].Value, "67")
}

func TestRouterMatchAny(t *testing.T) {

	l := New()
	path1 := "/github/"
	path2 := "/github/*"
	path3 := "/users/*"

	l.Get(path1, func(c Context) {
		c.Response().Write([]byte(c.Request().URL.Path))
	})

	l.Get(path2, func(c Context) {
		c.Response().Write([]byte(c.Request().URL.Path))
	})

	l.Get(path3, func(c Context) {
		c.Response().Write([]byte(c.Request().URL.Path))
	})

	code, body := request(GET, "/github/", l)
	Equal(t, code, http.StatusOK)
	Equal(t, body, path1)

	code, body = request(GET, "/github/department", l)
	Equal(t, code, http.StatusOK)
	Equal(t, body, "/github/department")

	code, body = request(GET, "/users/joe", l)
	Equal(t, code, http.StatusOK)
	Equal(t, body, "/users/joe")

}

func TestRouterMicroParam(t *testing.T) {
	var p Params

	l := New()
	l.Get("/:a/:b/:c", func(c Context) {
		p = c.Params()
	})
	code, _ := request(GET, "/1/2/3", l)
	Equal(t, code, http.StatusOK)
	Equal(t, "1", p[0].Value)
	Equal(t, "2", p[1].Value)
	Equal(t, "3", p[2].Value)

}

func TestRouterMixParamMatchAny(t *testing.T) {
	var p Params

	l := New()

	//Route
	l.Get("/users/:id/*", func(c Context) {
		c.Response().Write([]byte(c.Request().URL.Path))
		p = c.Params()
	})
	code, body := request(GET, "/users/joe/comments", l)
	Equal(t, code, http.StatusOK)
	Equal(t, "joe", p[0].Value)
	Equal(t, "/users/joe/comments", body)
}

func request(method, path string, l *LARS) (int, string) {
	r, _ := http.NewRequest(method, path, nil)
	w := httptest.NewRecorder()
	l.serveHTTP(w, r)
	return w.Code, w.Body.String()
}
<|endoftext|>


<commit_before>package ldap

import (
	"encoding/hex"
	"fmt"
	"regexp"
	"strings"

	l "github.com/go-ldap/ldap"
	"github.com/pivotalservices/cf-mgmt/config"
	"github.com/xchapter7x/lo"
)

var (
	attributes = []string{"*"}
)

var (
	userRegexp          = regexp.MustCompile(",[A-Z]+=")
	escapeFilterRegex   = regexp.MustCompile(`([\\\(\)\*\0-\37\177-\377])`)
	unescapeFilterRegex = regexp.MustCompile(`\\([\da-fA-F]{2}|[()\\*])`) // only match \[)*\] or \xx x=a-fA-F
)

const (
	groupFilter                 = "(cn=%s)"
	userFilter                  = "(%s=%s)"
	userFilterWithObjectClass   = "(&(objectclass=%s)(%s=%s))"
	userDNFilter                = "(%s)"
	userDNFilterWithObjectClass = "(&(objectclass=%s)(%s))"
)

func NewManager(ldapConfig *config.LdapConfig) (Manager, error) {
	conn, err := CreateConnection(ldapConfig)
	if err != nil {
		return nil, err
	}
	return &DefaultManager{
		Config:     ldapConfig,
		Connection: conn,
	}, nil
}

func (m *DefaultManager) GetUserDNs(groupName string) ([]string, error) {
	filter := fmt.Sprintf(groupFilter, l.EscapeFilter(groupName))
	var groupEntry *l.Entry
	lo.G.Debug("Searching for group:", filter)
	lo.G.Debug("Using group search base:", m.Config.GroupSearchBase)

	search := l.NewSearchRequest(
		m.Config.GroupSearchBase,
		l.ScopeWholeSubtree, l.NeverDerefAliases, 0, 0, false,
		filter,
		attributes,
		nil)
	sr, err := m.Connection.Search(search)
	if err != nil {
		lo.G.Error(err)
		return nil, err
	}

	if len(sr.Entries) == 0 {
		lo.G.Errorf("group not found: %s", groupName)
		return []string{}, nil
	}
	if len(sr.Entries) > 1 {
		lo.G.Errorf("multiple groups found for: %s", groupName)
		return []string{}, nil
	}

	groupEntry = sr.Entries[0]
	userDNList := groupEntry.GetAttributeValues(m.Config.GroupAttribute)
	if len(userDNList) == 0 {
		lo.G.Warningf("No users found under group: %s", groupName)
	}

	userMap := make(map[string]string)
	for _, userDN := range userDNList {
		group, cn, err := m.IsGroup(userDN)
		if err != nil {
			return nil, err
		}
		if group {
			if err != nil {
				return nil, err
			}
			nestedUsers, err := m.GetUserDNs(cn)
			if err != nil {
				return nil, err
			}
			for _, nestedUser := range nestedUsers {
				userMap[nestedUser] = nestedUser
			}
		} else {
			userMap[userDN] = userDN
		}
	}
	var userList []string
	for _, userDN := range userMap {
		userList = append(userList, userDN)
	}
	return userList, nil
}

func (m *DefaultManager) getCN(userDN string) (string, error) {
	indexes := userRegexp.FindStringIndex(strings.ToUpper(userDN))
	if len(indexes) == 0 {
		return "", fmt.Errorf("cannot find CN for DN: %s", userDN)
	}
	cn := strings.Replace(userDN[:indexes[0]], "cn=", "", 1)
	cnTemp := UnescapeFilterValue(cn)
	lo.G.Debug("CN unescaped:", cnTemp)

	escapedCN := l.EscapeFilter(strings.Replace(cnTemp, "\\", "", -1))
	lo.G.Debug("CN escaped:", escapedCN)
	return escapedCN, nil
}
func (m *DefaultManager) IsGroup(userDN string) (bool, string, error) {
	if strings.Contains(userDN, m.Config.GroupSearchBase) {
		cn, err := m.getCN(userDN)
		if err != nil {
			return false, "", err
		}
		filter := fmt.Sprintf(groupFilter, cn)
		search := l.NewSearchRequest(
			m.Config.GroupSearchBase,
			l.ScopeWholeSubtree, l.NeverDerefAliases, 0, 0, false,
			filter,
			attributes,
			nil)
		sr, err := m.Connection.Search(search)
		if err != nil {
			return false, "", err
		}
		lo.G.Debugf("Found %d entries for group filter", len(sr.Entries), filter)
		return len(sr.Entries) == 1, cn, nil
	} else {
		return false, "", nil
	}
}

func (m *DefaultManager) GetUserByDN(userDN string) (*User, error) {
	lo.G.Debug("User DN:", userDN)
	indexes := userRegexp.FindStringIndex(strings.ToUpper(userDN))
	if len(indexes) == 0 {
		return nil, fmt.Errorf("cannot find CN for user DN: %s", userDN)
	}
	index := indexes[0]
	userCNTemp := UnescapeFilterValue(userDN[:index])
	lo.G.Debug("CN unescaped:", userCNTemp)

	userCN := l.EscapeFilter(strings.Replace(userCNTemp, "\\", "", 1))
	lo.G.Debug("CN escaped:", userCN)
	filter := m.getUserFilterWithCN(userCN)
	return m.searchUser(filter, userDN[index+1:], "")
}

func (m *DefaultManager) GetUserByID(userID string) (*User, error) {
	filter := m.getUserFilter(userID)
	lo.G.Debug("Searching for user:", filter)
	lo.G.Debug("Using user search base:", m.Config.UserSearchBase)
	return m.searchUser(filter, m.Config.UserSearchBase, userID)
}

func (m *DefaultManager) searchUser(filter, searchBase, userID string) (*User, error) {
	lo.G.Debugf("Searching with filter %s", filter)
	search := l.NewSearchRequest(
		searchBase,
		l.ScopeWholeSubtree, l.NeverDerefAliases, 0, 0, false,
		filter,
		attributes,
		nil)

	sr, err := m.Connection.Search(search)
	if err != nil {
		lo.G.Error(err)
		return nil, err
	}

	if (len(sr.Entries)) == 1 {
		entry := sr.Entries[0]
		user := &User{
			UserDN: entry.DN,
			Email:  entry.GetAttributeValue(m.Config.UserMailAttribute),
		}
		if userID != "" {
			user.UserID = userID
		} else {
			user.UserID = entry.GetAttributeValue(m.Config.UserNameAttribute)
		}
		lo.G.Debugf("Search filter %s returned userDN [%s], email [%s], userID [%s]", filter, user.UserDN, user.Email, user.UserID)
		return user, nil
	}
	lo.G.Errorf("Found %d number of entries for filter %s", len(sr.Entries), filter)
	return nil, nil
}

func UnescapeFilterValue(filter string) string {
	repl := unescapeFilterRegex.ReplaceAllFunc(
		[]byte(filter),
		func(match []byte) []byte {
			// \( \) \\ \*
			if len(match) == 2 {
				return []byte{match[1]}
			}
			// had issues with Decode, TODO fix to use Decode?.
			res, _ := hex.DecodeString(string(match[1:]))
			return res
		},
	)
	return string(repl)
}

func (m *DefaultManager) getUserFilter(userID string) string {
	if m.Config.UserObjectClass == "" {
		return fmt.Sprintf(userFilter, m.Config.UserNameAttribute, userID)
	}
	return fmt.Sprintf(userFilterWithObjectClass, m.Config.UserObjectClass, m.Config.UserNameAttribute, userID)
}

func (m *DefaultManager) getUserFilterWithCN(cn string) string {
	if m.Config.UserObjectClass == "" {
		return fmt.Sprintf(userDNFilter, cn)
	}
	return fmt.Sprintf(userDNFilterWithObjectClass, m.Config.UserObjectClass, cn)
}

func (m *DefaultManager) Close() {
	if m.Connection != nil {
		m.Connection.Close()
	}
}
<commit_msg>fixing search filter for nested group searches<commit_after>package ldap

import (
	"encoding/hex"
	"fmt"
	"regexp"
	"strings"

	l "github.com/go-ldap/ldap"
	"github.com/pivotalservices/cf-mgmt/config"
	"github.com/xchapter7x/lo"
)

var (
	attributes = []string{"*"}
)

var (
	userRegexp          = regexp.MustCompile(",[A-Z]+=")
	escapeFilterRegex   = regexp.MustCompile(`([\\\(\)\*\0-\37\177-\377])`)
	unescapeFilterRegex = regexp.MustCompile(`\\([\da-fA-F]{2}|[()\\*])`) // only match \[)*\] or \xx x=a-fA-F
)

const (
	groupFilter                 = "(cn=%s)"
	userFilter                  = "(%s=%s)"
	userFilterWithObjectClass   = "(&(objectclass=%s)(%s=%s))"
	userDNFilter                = "(%s)"
	userDNFilterWithObjectClass = "(&(objectclass=%s)(%s))"
)

func NewManager(ldapConfig *config.LdapConfig) (Manager, error) {
	conn, err := CreateConnection(ldapConfig)
	if err != nil {
		return nil, err
	}
	return &DefaultManager{
		Config:     ldapConfig,
		Connection: conn,
	}, nil
}

func (m *DefaultManager) GetUserDNs(groupName string) ([]string, error) {
	filter := fmt.Sprintf(groupFilter, l.EscapeFilter(groupName))
	var groupEntry *l.Entry
	lo.G.Debug("Searching for group:", filter)
	lo.G.Debug("Using group search base:", m.Config.GroupSearchBase)

	search := l.NewSearchRequest(
		m.Config.GroupSearchBase,
		l.ScopeWholeSubtree, l.NeverDerefAliases, 0, 0, false,
		filter,
		attributes,
		nil)
	sr, err := m.Connection.Search(search)
	if err != nil {
		lo.G.Error(err)
		return nil, err
	}

	if len(sr.Entries) == 0 {
		lo.G.Errorf("group not found: %s", groupName)
		return []string{}, nil
	}
	if len(sr.Entries) > 1 {
		lo.G.Errorf("multiple groups found for: %s", groupName)
		return []string{}, nil
	}

	groupEntry = sr.Entries[0]
	userDNList := groupEntry.GetAttributeValues(m.Config.GroupAttribute)
	if len(userDNList) == 0 {
		lo.G.Warningf("No users found under group: %s", groupName)
	}

	userMap := make(map[string]string)
	for _, userDN := range userDNList {
		group, cn, err := m.IsGroup(userDN)
		if err != nil {
			return nil, err
		}
		if group {
			if err != nil {
				return nil, err
			}
			nestedUsers, err := m.GetUserDNs(cn)
			if err != nil {
				return nil, err
			}
			for _, nestedUser := range nestedUsers {
				userMap[nestedUser] = nestedUser
			}
		} else {
			userMap[userDN] = userDN
		}
	}
	var userList []string
	for _, userDN := range userMap {
		userList = append(userList, userDN)
	}
	return userList, nil
}

func (m *DefaultManager) getCN(userDN string) (string, error) {
	indexes := userRegexp.FindStringIndex(strings.ToUpper(userDN))
	if len(indexes) == 0 {
		return "", fmt.Errorf("cannot find CN for DN: %s", userDN)
	}
	cn := strings.Replace(userDN[:indexes[0]], "cn=", "", 1)
	cnTemp := UnescapeFilterValue(cn)
	lo.G.Debug("CN unescaped:", cnTemp)

	escapedCN := l.EscapeFilter(strings.Replace(cnTemp, "\\", "", -1))
	lo.G.Debug("CN escaped:", escapedCN)
	return escapedCN, nil
}
func (m *DefaultManager) IsGroup(userDN string) (bool, string, error) {
	if strings.Contains(userDN, m.Config.GroupSearchBase) {
		cn, err := m.getCN(userDN)
		if err != nil {
			return false, "", err
		}
		filter := fmt.Sprintf("(%s)", cn)
		search := l.NewSearchRequest(
			m.Config.GroupSearchBase,
			l.ScopeWholeSubtree, l.NeverDerefAliases, 0, 0, false,
			filter,
			attributes,
			nil)
		sr, err := m.Connection.Search(search)
		if err != nil {
			return false, "", err
		}
		lo.G.Debugf("Found %d entries for group filter", len(sr.Entries), filter)
		return len(sr.Entries) == 1, cn, nil
	} else {
		return false, "", nil
	}
}

func (m *DefaultManager) GetUserByDN(userDN string) (*User, error) {
	lo.G.Debug("User DN:", userDN)
	indexes := userRegexp.FindStringIndex(strings.ToUpper(userDN))
	if len(indexes) == 0 {
		return nil, fmt.Errorf("cannot find CN for user DN: %s", userDN)
	}
	index := indexes[0]
	userCNTemp := UnescapeFilterValue(userDN[:index])
	lo.G.Debug("CN unescaped:", userCNTemp)

	userCN := l.EscapeFilter(strings.Replace(userCNTemp, "\\", "", 1))
	lo.G.Debug("CN escaped:", userCN)
	filter := m.getUserFilterWithCN(userCN)
	return m.searchUser(filter, userDN[index+1:], "")
}

func (m *DefaultManager) GetUserByID(userID string) (*User, error) {
	filter := m.getUserFilter(userID)
	lo.G.Debug("Searching for user:", filter)
	lo.G.Debug("Using user search base:", m.Config.UserSearchBase)
	return m.searchUser(filter, m.Config.UserSearchBase, userID)
}

func (m *DefaultManager) searchUser(filter, searchBase, userID string) (*User, error) {
	lo.G.Debugf("Searching with filter %s", filter)
	search := l.NewSearchRequest(
		searchBase,
		l.ScopeWholeSubtree, l.NeverDerefAliases, 0, 0, false,
		filter,
		attributes,
		nil)

	sr, err := m.Connection.Search(search)
	if err != nil {
		lo.G.Error(err)
		return nil, err
	}

	if (len(sr.Entries)) == 1 {
		entry := sr.Entries[0]
		user := &User{
			UserDN: entry.DN,
			Email:  entry.GetAttributeValue(m.Config.UserMailAttribute),
		}
		if userID != "" {
			user.UserID = userID
		} else {
			user.UserID = entry.GetAttributeValue(m.Config.UserNameAttribute)
		}
		lo.G.Debugf("Search filter %s returned userDN [%s], email [%s], userID [%s]", filter, user.UserDN, user.Email, user.UserID)
		return user, nil
	}
	lo.G.Errorf("Found %d number of entries for filter %s", len(sr.Entries), filter)
	return nil, nil
}

func UnescapeFilterValue(filter string) string {
	repl := unescapeFilterRegex.ReplaceAllFunc(
		[]byte(filter),
		func(match []byte) []byte {
			// \( \) \\ \*
			if len(match) == 2 {
				return []byte{match[1]}
			}
			// had issues with Decode, TODO fix to use Decode?.
			res, _ := hex.DecodeString(string(match[1:]))
			return res
		},
	)
	return string(repl)
}

func (m *DefaultManager) getUserFilter(userID string) string {
	if m.Config.UserObjectClass == "" {
		return fmt.Sprintf(userFilter, m.Config.UserNameAttribute, userID)
	}
	return fmt.Sprintf(userFilterWithObjectClass, m.Config.UserObjectClass, m.Config.UserNameAttribute, userID)
}

func (m *DefaultManager) getUserFilterWithCN(cn string) string {
	if m.Config.UserObjectClass == "" {
		return fmt.Sprintf(userDNFilter, cn)
	}
	return fmt.Sprintf(userDNFilterWithObjectClass, m.Config.UserObjectClass, cn)
}

func (m *DefaultManager) Close() {
	if m.Connection != nil {
		m.Connection.Close()
	}
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"strings"

	"github.com/coreos/fleet/job"
)

// Destroy units for a given target
func (c *FleetClient) Destroy(targets []string) error {
	for _, target := range targets {
		// check if the unit exists
		if _, err := c.Units(target); err != nil {
			return err
		}
		component, num, err := splitTarget(target)
		if err != nil {
			return err
		}
		if strings.HasSuffix(component, "-data") {
			err = c.destroyDataUnit(component)
		} else {
			err = c.destroyServiceUnit(component, num)
		}
		if err != nil {
			return err
		}
	}
	return nil
}

func (c *FleetClient) destroyServiceUnit(component string, num int) (err error) {
	name, err := formatUnitName(component, num)
	if err != nil {
		return err
	}
	desiredState := string(job.JobStateInactive)
	err = c.Fleet.SetUnitTargetState(name, desiredState)
	if err != nil {
		return err
	}
	outchan, errchan := waitForUnitStates([]string{name}, desiredState)
	err = printUnitState(name, outchan, errchan)
	if err != nil {
		return err
	}
	if err = c.Fleet.DestroyUnit(name); err != nil {
		return fmt.Errorf("failed destroying job %s: %v", name, err)
	}
	return err
}

func (c *FleetClient) destroyDataUnit(component string) (err error) {
	name, err := formatUnitName(component, 0)
	if err != nil {
		return err
	}
	desiredState := string(job.JobStateInactive)
	err = c.Fleet.SetUnitTargetState(name, desiredState)
	if err != nil {
		return err
	}
	outchan, errchan := waitForUnitStates([]string{name}, desiredState)
	err = printUnitState(name, outchan, errchan)
	if err != nil {
		return err
	}
	if err = c.Fleet.DestroyUnit(name); err != nil {
		return fmt.Errorf("failed destroying job %s: %v", name, err)
	}
	return err

}
<commit_msg>fix(client): destroy all units if none specified<commit_after>package client

import (
	"fmt"
	"strings"

	"github.com/coreos/fleet/job"
)

// Destroy units for a given target
func (c *FleetClient) Destroy(targets []string) error {
	for _, target := range targets {
		// check if the unit exists
		units, err := c.Units(target)
		if err != nil {
			return err
		}
		component, num, err := splitTarget(target)
		if err != nil {
			return err
		}
		// if no number is specified, destroy ALL THE UNITS!
		if num == 0 {
			num = len(units)
		}
		if strings.HasSuffix(component, "-data") {
			err = c.destroyDataUnit(component)
		} else {
			err = c.destroyServiceUnit(component, num)
		}
		if err != nil {
			return err
		}
	}
	return nil
}

func (c *FleetClient) destroyServiceUnit(component string, num int) (err error) {
	name, err := formatUnitName(component, num)
	if err != nil {
		return err
	}
	desiredState := string(job.JobStateInactive)
	err = c.Fleet.SetUnitTargetState(name, desiredState)
	if err != nil {
		return err
	}
	outchan, errchan := waitForUnitStates([]string{name}, desiredState)
	err = printUnitState(name, outchan, errchan)
	if err != nil {
		return err
	}
	if err = c.Fleet.DestroyUnit(name); err != nil {
		return fmt.Errorf("failed destroying job %s: %v", name, err)
	}
	return err
}

func (c *FleetClient) destroyDataUnit(component string) (err error) {
	name, err := formatUnitName(component, 0)
	if err != nil {
		return err
	}
	desiredState := string(job.JobStateInactive)
	err = c.Fleet.SetUnitTargetState(name, desiredState)
	if err != nil {
		return err
	}
	outchan, errchan := waitForUnitStates([]string{name}, desiredState)
	err = printUnitState(name, outchan, errchan)
	if err != nil {
		return err
	}
	if err = c.Fleet.DestroyUnit(name); err != nil {
		return fmt.Errorf("failed destroying job %s: %v", name, err)
	}
	return err

}
<|endoftext|>


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

package client

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"path"

	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
	"github.com/coreos/etcd/pkg/types"
)

var (
	defaultV2MembersPrefix = "/v2/members"
)

type Member httptypes.Member

// NewMembersAPI constructs a new MembersAPI that uses HTTP to
// interact with etcd's membership API.
func NewMembersAPI(c Client) MembersAPI {
	return &httpMembersAPI{
		client: c,
	}
}

type MembersAPI interface {
	List(ctx context.Context) ([]Member, error)
	Add(ctx context.Context, peerURL string) (*Member, error)
	Remove(ctx context.Context, mID string) error
}

type httpMembersAPI struct {
	client httpClient
}

func (m *httpMembersAPI) List(ctx context.Context) ([]Member, error) {
	req := &membersAPIActionList{}
	resp, body, err := m.client.Do(ctx, req)
	if err != nil {
		return nil, err
	}

	if err := assertStatusCode(resp.StatusCode, http.StatusOK); err != nil {
		return nil, err
	}

	var mCollection httptypes.MemberCollection
	if err := json.Unmarshal(body, &mCollection); err != nil {
		return nil, err
	}

	ms := make([]Member, len(mCollection))
	for i, m := range mCollection {
		m := Member(m)
		ms[i] = m
	}
	return ms, nil
}

func (m *httpMembersAPI) Add(ctx context.Context, peerURL string) (*Member, error) {
	urls, err := types.NewURLs([]string{peerURL})
	if err != nil {
		return nil, err
	}

	req := &membersAPIActionAdd{peerURLs: urls}
	resp, body, err := m.client.Do(ctx, req)
	if err != nil {
		return nil, err
	}

	if err := assertStatusCode(resp.StatusCode, http.StatusCreated, http.StatusConflict); err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusCreated {
		var httperr httptypes.HTTPError
		if err := json.Unmarshal(body, &httperr); err != nil {
			return nil, err
		}
		return nil, httperr
	}

	var memb Member
	if err := json.Unmarshal(body, &memb); err != nil {
		return nil, err
	}

	return &memb, nil
}

func (m *httpMembersAPI) Remove(ctx context.Context, memberID string) error {
	req := &membersAPIActionRemove{memberID: memberID}
	resp, _, err := m.client.Do(ctx, req)
	if err != nil {
		return err
	}

	return assertStatusCode(resp.StatusCode, http.StatusNoContent)
}

type membersAPIActionList struct{}

func (l *membersAPIActionList) HTTPRequest(ep url.URL) *http.Request {
	u := v2MembersURL(ep)
	req, _ := http.NewRequest("GET", u.String(), nil)
	return req
}

type membersAPIActionRemove struct {
	memberID string
}

func (d *membersAPIActionRemove) HTTPRequest(ep url.URL) *http.Request {
	u := v2MembersURL(ep)
	u.Path = path.Join(u.Path, d.memberID)
	req, _ := http.NewRequest("DELETE", u.String(), nil)
	return req
}

type membersAPIActionAdd struct {
	peerURLs types.URLs
}

func (a *membersAPIActionAdd) HTTPRequest(ep url.URL) *http.Request {
	u := v2MembersURL(ep)
	m := httptypes.MemberCreateRequest{PeerURLs: a.peerURLs}
	b, _ := json.Marshal(&m)
	req, _ := http.NewRequest("POST", u.String(), bytes.NewReader(b))
	req.Header.Set("Content-Type", "application/json")
	return req
}

func assertStatusCode(got int, want ...int) (err error) {
	for _, w := range want {
		if w == got {
			return nil
		}
	}
	return fmt.Errorf("unexpected status code %d", got)
}

// v2MembersURL add the necessary path to the provided endpoint
// to route requests to the default v2 members API.
func v2MembersURL(ep url.URL) *url.URL {
	ep.Path = path.Join(ep.Path, defaultV2MembersPrefix)
	return &ep
}
<commit_msg>client: document MembersAPI methods<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package client

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"path"

	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
	"github.com/coreos/etcd/pkg/types"
)

var (
	defaultV2MembersPrefix = "/v2/members"
)

type Member httptypes.Member

// NewMembersAPI constructs a new MembersAPI that uses HTTP to
// interact with etcd's membership API.
func NewMembersAPI(c Client) MembersAPI {
	return &httpMembersAPI{
		client: c,
	}
}

type MembersAPI interface {
	// List enumerates the current cluster membership
	List(ctx context.Context) ([]Member, error)

	// Add instructs etcd to accept a new Member into the cluster
	Add(ctx context.Context, peerURL string) (*Member, error)

	// Remove demotes an existing Member out of the cluster
	Remove(ctx context.Context, mID string) error
}

type httpMembersAPI struct {
	client httpClient
}

func (m *httpMembersAPI) List(ctx context.Context) ([]Member, error) {
	req := &membersAPIActionList{}
	resp, body, err := m.client.Do(ctx, req)
	if err != nil {
		return nil, err
	}

	if err := assertStatusCode(resp.StatusCode, http.StatusOK); err != nil {
		return nil, err
	}

	var mCollection httptypes.MemberCollection
	if err := json.Unmarshal(body, &mCollection); err != nil {
		return nil, err
	}

	ms := make([]Member, len(mCollection))
	for i, m := range mCollection {
		m := Member(m)
		ms[i] = m
	}
	return ms, nil
}

func (m *httpMembersAPI) Add(ctx context.Context, peerURL string) (*Member, error) {
	urls, err := types.NewURLs([]string{peerURL})
	if err != nil {
		return nil, err
	}

	req := &membersAPIActionAdd{peerURLs: urls}
	resp, body, err := m.client.Do(ctx, req)
	if err != nil {
		return nil, err
	}

	if err := assertStatusCode(resp.StatusCode, http.StatusCreated, http.StatusConflict); err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusCreated {
		var httperr httptypes.HTTPError
		if err := json.Unmarshal(body, &httperr); err != nil {
			return nil, err
		}
		return nil, httperr
	}

	var memb Member
	if err := json.Unmarshal(body, &memb); err != nil {
		return nil, err
	}

	return &memb, nil
}

func (m *httpMembersAPI) Remove(ctx context.Context, memberID string) error {
	req := &membersAPIActionRemove{memberID: memberID}
	resp, _, err := m.client.Do(ctx, req)
	if err != nil {
		return err
	}

	return assertStatusCode(resp.StatusCode, http.StatusNoContent)
}

type membersAPIActionList struct{}

func (l *membersAPIActionList) HTTPRequest(ep url.URL) *http.Request {
	u := v2MembersURL(ep)
	req, _ := http.NewRequest("GET", u.String(), nil)
	return req
}

type membersAPIActionRemove struct {
	memberID string
}

func (d *membersAPIActionRemove) HTTPRequest(ep url.URL) *http.Request {
	u := v2MembersURL(ep)
	u.Path = path.Join(u.Path, d.memberID)
	req, _ := http.NewRequest("DELETE", u.String(), nil)
	return req
}

type membersAPIActionAdd struct {
	peerURLs types.URLs
}

func (a *membersAPIActionAdd) HTTPRequest(ep url.URL) *http.Request {
	u := v2MembersURL(ep)
	m := httptypes.MemberCreateRequest{PeerURLs: a.peerURLs}
	b, _ := json.Marshal(&m)
	req, _ := http.NewRequest("POST", u.String(), bytes.NewReader(b))
	req.Header.Set("Content-Type", "application/json")
	return req
}

func assertStatusCode(got int, want ...int) (err error) {
	for _, w := range want {
		if w == got {
			return nil
		}
	}
	return fmt.Errorf("unexpected status code %d", got)
}

// v2MembersURL add the necessary path to the provided endpoint
// to route requests to the default v2 members API.
func v2MembersURL(ep url.URL) *url.URL {
	ep.Path = path.Join(ep.Path, defaultV2MembersPrefix)
	return &ep
}
<|endoftext|>


<commit_before>// Copyright 2013 Xing Xing <mikespook@gmail.com>.
// All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package client

import (
	"encoding/binary"
)

// request
type request struct {
	DataType uint32
	Data     []byte
}

// Encode a Request to byte slice
func (req *request) Encode() (data []byte) {
	l := len(req.Data)       // length of data
	tl := l + MIN_PACKET_LEN // add 12 bytes head
	data = getBuffer(tl)
	copy(data[:4], REQ_STR)
	binary.BigEndian.PutUint32(data[4:8], req.DataType)
	binary.BigEndian.PutUint32(data[8:12], uint32(l))
	copy(data[MIN_PACKET_LEN:], req.Data)
	return
}

func getRequest() (req *request) {
	// TODO add a pool
	req = &request{}
	return
}

func getJob(id string, funcname, data []byte) (req *request) {
	req = getRequest()
	a := len(funcname)
	b := len(id)
	c := len(data)
	l := a + b + c + 2
	req.Data = getBuffer(l)
	copy(req.Data[0:a], funcname)
	copy(req.Data[a+1:a+b+1], []byte(id))
	copy(req.Data[a+b+1:a+b+c+1], data)
	return
}
<commit_msg>fixed building package issue<commit_after>// Copyright 2013 Xing Xing <mikespook@gmail.com>.
// All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package client

import (
	"encoding/binary"
)

// request
type request struct {
	DataType uint32
	Data     []byte
}

// Encode a Request to byte slice
func (req *request) Encode() (data []byte) {
	l := len(req.Data)       // length of data
	tl := l + MIN_PACKET_LEN // add 12 bytes head
	data = getBuffer(tl)
	copy(data[:4], REQ_STR)
	binary.BigEndian.PutUint32(data[4:8], req.DataType)
	binary.BigEndian.PutUint32(data[8:12], uint32(l))
	copy(data[MIN_PACKET_LEN:], req.Data)
	return
}

func getRequest() (req *request) {
	// TODO add a pool
	req = &request{}
	return
}

func getJob(id string, funcname, data []byte) (req *request) {
	req = getRequest()
	a := len(funcname)
	b := len(id)
	c := len(data)
	l := a + b + c + 2
	req.Data = getBuffer(l)
	copy(req.Data[0:a], funcname)
	copy(req.Data[a+1:a+b+1], []byte(id))
	copy(req.Data[a+b+2:], data)
	return
}
<|endoftext|>


<commit_before>package lib

import (
	drive "code.google.com/p/google-api-go-client/drive/v2"
	"log"
	"strings"
	"sync"
)

// refreshFileIndex refreshes the id -> DriveFile pairs it retrieves from the drive api
func refreshFileIndex() {
	// create tmp map to replace fileIndex
	tmpFileIndex := make(map[string]*drive.File)
	// get the file list from the google api
	f, err := service.Files.List().Do()
	if err != nil {
		log.Println(err)
		return
	}
	list := f.Items
	for i := range list {
		if list[i] == nil {
			log.Println("here")
		}
		tmpFileIndex[list[i].Id] = list[i]
	}
	fileIndex = tmpFileIndex
}

// refreshDirIndex refreshes the id -> pairs it retrives from the drive api
func refreshChildIndex() {
	// get the file list from the google api
	f, err := service.Files.List().Do()
	if err != nil {
		log.Println(err)
		return
	}
	list := f.Items

	// make new tmp maps
	tmpChildIndex := make(map[string]*drive.ChildList)
	parents := make(map[string]*drive.File)

	for i := range list {
		if strings.Contains(list[i].MimeType, "folder") {
			parents[list[i].Id] = list[i]
		}
	}
	// collect the children
	var c *drive.ChildList
	var cErr error
	for _, v := range parents {
		c, cErr = service.Children.List(v.Id).Do()
		if cErr != nil {
			log.Println(cErr)
		} else {
			tmpChildIndex[v.Id] = c
		}
	}
	// collect the children for the root directory
	c, cErr = service.Children.List("root").Do()
	if cErr != nil {
		log.Println(err)
	} else {
		tmpChildIndex["root"] = c
	}

	// replace old index with new
	childIndex = tmpChildIndex
}

// refreshNameToFile refreshes the nameToFile lookup map
func refreshNameToFile() {
	tmpNameToFile := make(map[string]*DriveFile)
	for _, v := range fileIndex {
		tmpNameToFile[v.Title] = &DriveFile{File: v, Root: false, Mutex: new(sync.Mutex)}
	}
	nameToFile = tmpNameToFile
}

// refreshNameToDir refreshes the nameToDir lookup map
func refreshNameToDir() {
	tmpNameToDir := make(map[string]*DriveDir)
	for _, v := range fileIndex {
		if strings.Contains(v.MimeType, "folder") {
			tmpNameToDir[v.Title] = &DriveDir{Dir: v, Root: false}
		}
	}
	nameToDir = tmpNameToDir
}

func refreshAll() {
	refreshFileIndex()
	refreshChildIndex()
	refreshNameToFile()
	refreshNameToDir()
}
<commit_msg>removed debug prints<commit_after>package lib

import (
	drive "code.google.com/p/google-api-go-client/drive/v2"
	"log"
	"strings"
	"sync"
)

// refreshFileIndex refreshes the id -> DriveFile pairs it retrieves from the drive api
func refreshFileIndex() {
	// create tmp map to replace fileIndex
	tmpFileIndex := make(map[string]*drive.File)
	// get the file list from the google api
	f, err := service.Files.List().Do()
	if err != nil {
		log.Println(err)
		return
	}
	list := f.Items
	for i := range list {
		tmpFileIndex[list[i].Id] = list[i]
	}
	fileIndex = tmpFileIndex
}

// refreshDirIndex refreshes the id -> pairs it retrives from the drive api
func refreshChildIndex() {
	// get the file list from the google api
	f, err := service.Files.List().Do()
	if err != nil {
		log.Println(err)
		return
	}
	list := f.Items

	// make new tmp maps
	tmpChildIndex := make(map[string]*drive.ChildList)
	parents := make(map[string]*drive.File)

	for i := range list {
		if strings.Contains(list[i].MimeType, "folder") {
			parents[list[i].Id] = list[i]
		}
	}
	// collect the children
	var c *drive.ChildList
	var cErr error
	for _, v := range parents {
		c, cErr = service.Children.List(v.Id).Do()
		if cErr != nil {
			log.Println(cErr)
		} else {
			tmpChildIndex[v.Id] = c
		}
	}
	// collect the children for the root directory
	c, cErr = service.Children.List("root").Do()
	if cErr != nil {
		log.Println(err)
	} else {
		tmpChildIndex["root"] = c
	}

	// replace old index with new
	childIndex = tmpChildIndex
}

// refreshNameToFile refreshes the nameToFile lookup map
func refreshNameToFile() {
	tmpNameToFile := make(map[string]*DriveFile)
	for _, v := range fileIndex {
		tmpNameToFile[v.Title] = &DriveFile{File: v, Root: false, Mutex: new(sync.Mutex)}
	}
	nameToFile = tmpNameToFile
}

// refreshNameToDir refreshes the nameToDir lookup map
func refreshNameToDir() {
	tmpNameToDir := make(map[string]*DriveDir)
	for _, v := range fileIndex {
		if strings.Contains(v.MimeType, "folder") {
			tmpNameToDir[v.Title] = &DriveDir{Dir: v, Root: false}
		}
	}
	nameToDir = tmpNameToDir
}

func refreshAll() {
	refreshFileIndex()
	refreshChildIndex()
	refreshNameToFile()
	refreshNameToDir()
}
<|endoftext|>


<commit_before>// Copyright 2017 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.

// +build !plan9,!windows

// Test handling of Go-allocated signal stacks when calling from
// C-created threads with and without signal stacks. (See issue
// #22930.)

package main

/*
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>

#ifndef MAP_STACK
#define MAP_STACK 0
#endif

extern void SigStackCallback();

static void* WithSigStack(void* arg __attribute__((unused))) {
	// Set up an alternate system stack.
	void* base = mmap(0, SIGSTKSZ, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON|MAP_STACK, -1, 0);
	if (base == MAP_FAILED) {
		perror("mmap failed");
		abort();
	}
	stack_t st = {}, ost = {};
	st.ss_sp = (char*)base;
	st.ss_flags = 0;
	st.ss_size = SIGSTKSZ;
	if (sigaltstack(&st, &ost) < 0) {
		perror("sigaltstack failed");
		abort();
	}

	// Call Go.
	SigStackCallback();

	// Disable signal stack and protect it so we can detect reuse.
	if (ost.ss_flags & SS_DISABLE) {
		// Darwin libsystem has a bug where it checks ss_size
		// even if SS_DISABLE is set. (The kernel gets it right.)
		ost.ss_size = SIGSTKSZ;
	}
	if (sigaltstack(&ost, NULL) < 0) {
		perror("sigaltstack restore failed");
		abort();
	}
	mprotect(base, SIGSTKSZ, PROT_NONE);
	return NULL;
}

static void* WithoutSigStack(void* arg __attribute__((unused))) {
	SigStackCallback();
	return NULL;
}

static void DoThread(int sigstack) {
	pthread_t tid;
	if (sigstack) {
		pthread_create(&tid, NULL, WithSigStack, NULL);
	} else {
		pthread_create(&tid, NULL, WithoutSigStack, NULL);
	}
	pthread_join(tid, NULL);
}
*/
import "C"

func init() {
	register("SigStack", SigStack)
}

func SigStack() {
	C.DoThread(0)
	C.DoThread(1)
	C.DoThread(0)
	C.DoThread(1)
	println("OK")
}

var BadPtr *int

//export SigStackCallback
func SigStackCallback() {
	// Cause the Go signal handler to run.
	defer func() { recover() }()
	*BadPtr = 42
}
<commit_msg>runtime: don't use MAP_STACK in SigStack test<commit_after>// Copyright 2017 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.

// +build !plan9,!windows

// Test handling of Go-allocated signal stacks when calling from
// C-created threads with and without signal stacks. (See issue
// #22930.)

package main

/*
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>

extern void SigStackCallback();

static void* WithSigStack(void* arg __attribute__((unused))) {
	// Set up an alternate system stack.
	void* base = mmap(0, SIGSTKSZ, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
	if (base == MAP_FAILED) {
		perror("mmap failed");
		abort();
	}
	stack_t st = {}, ost = {};
	st.ss_sp = (char*)base;
	st.ss_flags = 0;
	st.ss_size = SIGSTKSZ;
	if (sigaltstack(&st, &ost) < 0) {
		perror("sigaltstack failed");
		abort();
	}

	// Call Go.
	SigStackCallback();

	// Disable signal stack and protect it so we can detect reuse.
	if (ost.ss_flags & SS_DISABLE) {
		// Darwin libsystem has a bug where it checks ss_size
		// even if SS_DISABLE is set. (The kernel gets it right.)
		ost.ss_size = SIGSTKSZ;
	}
	if (sigaltstack(&ost, NULL) < 0) {
		perror("sigaltstack restore failed");
		abort();
	}
	mprotect(base, SIGSTKSZ, PROT_NONE);
	return NULL;
}

static void* WithoutSigStack(void* arg __attribute__((unused))) {
	SigStackCallback();
	return NULL;
}

static void DoThread(int sigstack) {
	pthread_t tid;
	if (sigstack) {
		pthread_create(&tid, NULL, WithSigStack, NULL);
	} else {
		pthread_create(&tid, NULL, WithoutSigStack, NULL);
	}
	pthread_join(tid, NULL);
}
*/
import "C"

func init() {
	register("SigStack", SigStack)
}

func SigStack() {
	C.DoThread(0)
	C.DoThread(1)
	C.DoThread(0)
	C.DoThread(1)
	println("OK")
}

var BadPtr *int

//export SigStackCallback
func SigStackCallback() {
	// Cause the Go signal handler to run.
	defer func() { recover() }()
	*BadPtr = 42
}
<|endoftext|>


<commit_before>package paths

import (
	"bytes"
	"fmt"
	"io"
	"testing"

	. "github.com/VonC/godbg"
	"github.com/VonC/senvgo/prgs"
	. "github.com/smartystreets/goconvey/convey"
)

func TestPath(t *testing.T) {

	FocusConvey("Tests for Path", t, func() {
		Convey("An empty path remains empty", func() {
			SetBuffers(nil)
			p := NewPath("")
			So(p.path, ShouldEqual, "")
		})

		Convey("An http path remains unchanged", func() {
			SetBuffers(nil)
			p := NewPath(`http://a\b/../c`)
			So(p.path, ShouldEqual, `http://a\b/../c`)
		})
		Convey("A path without trailing / must have one if it is an existing folder", func() {
			SetBuffers(nil)
			p := NewPath(`../paths`)
			So(p.path, ShouldEqual, `..\paths\`)
		})
		Convey("A path without trailing / must keep it even if it is not an existing folder", func() {
			SetBuffers(nil)
			p := NewPath(`xxx\`)
			p = NewPath(`xxx/`)
			So(p.path, ShouldEqual, `xxx\`)
		})

		FocusConvey("A Path can test if it is a Dir", func() {
			SetBuffers(nil)
			p := NewPath("")
			So(p.IsDir(), ShouldBeFalse)
		})
	})
}

type testPrg struct{ name string }

func (tp *testPrg) Name() string { return tp.name }

type testPathWriter struct{ b *bytes.Buffer }

type testWriter struct{ w io.Writer }

func (tw *testWriter) Write(p []byte) (n int, err error) {
	s := string(p)
	if s == "prg2" {
		return 0, fmt.Errorf("Error writing '%s'", s)
	}
	return tw.w.Write(p)
}

func (tpw *testPathWriter) WritePath(prgs []prgs.Prg, w io.Writer) error {
	if err := pw.WritePath(prgs, w); err != nil {
		return err
	}
	return nil
}

func TestMain(t *testing.T) {
	tpw := &testPathWriter{b: bytes.NewBuffer(nil)}
	prgs := []prgs.Prg{&testPrg{name: "prg1"}, &testPrg{name: "prg2"}}
	Convey("Tests for Path Writer", t, func() {

		Convey("A Path writer writes any empty path if no prgs", func() {
			SetBuffers(nil)
			err := tpw.WritePath(prgs, tpw.b)
			So(err, ShouldBeNil)
			So(tpw.b.String(), ShouldEqual, "prg1prg2")
		})

		Convey("A Path writer can report error during writing", func() {
			SetBuffers(nil)
			tpw.b = bytes.NewBuffer(nil)
			tw := &testWriter{w: tpw.b}
			err := tpw.WritePath(prgs, tw)
			So(err.Error(), ShouldEqual, "Error writing 'prg2'")
			So(tpw.b.String(), ShouldEqual, "prg1")
		})
	})
}
<commit_msg>PathWriter: test for no output<commit_after>package paths

import (
	"bytes"
	"fmt"
	"io"
	"testing"

	. "github.com/VonC/godbg"
	"github.com/VonC/senvgo/prgs"
	. "github.com/smartystreets/goconvey/convey"
)

func TestPath(t *testing.T) {

	FocusConvey("Tests for Path", t, func() {
		Convey("An empty path remains empty", func() {
			SetBuffers(nil)
			p := NewPath("")
			So(p.path, ShouldEqual, "")
		})

		Convey("An http path remains unchanged", func() {
			SetBuffers(nil)
			p := NewPath(`http://a\b/../c`)
			So(p.path, ShouldEqual, `http://a\b/../c`)
		})
		Convey("A path without trailing / must have one if it is an existing folder", func() {
			SetBuffers(nil)
			p := NewPath(`../paths`)
			So(p.path, ShouldEqual, `..\paths\`)
		})
		Convey("A path without trailing / must keep it even if it is not an existing folder", func() {
			SetBuffers(nil)
			p := NewPath(`xxx\`)
			p = NewPath(`xxx/`)
			So(p.path, ShouldEqual, `xxx\`)
		})

		FocusConvey("A Path can test if it is a Dir", func() {
			SetBuffers(nil)
			p := NewPath("")
			So(p.IsDir(), ShouldBeFalse)
		})
	})
}

type testPrg struct{ name string }

func (tp *testPrg) Name() string { return tp.name }

type testPathWriter struct{ b *bytes.Buffer }

type testWriter struct{ w io.Writer }

func (tw *testWriter) Write(p []byte) (n int, err error) {
	s := string(p)
	if s == "prg2" {
		return 0, fmt.Errorf("Error writing '%s'", s)
	}
	return tw.w.Write(p)
}

func (tpw *testPathWriter) WritePath(prgs []prgs.Prg, w io.Writer) error {
	if err := pw.WritePath(prgs, w); err != nil {
		return err
	}
	return nil
}

func TestMain(t *testing.T) {
	tpw := &testPathWriter{b: bytes.NewBuffer(nil)}
	prgs := []prgs.Prg{&testPrg{name: "prg1"}, &testPrg{name: "prg2"}}
	Convey("Tests for Path Writer", t, func() {

		Convey("A Path writer writes any empty path if no prgs", func() {
			SetBuffers(nil)
			err := tpw.WritePath(prgs, tpw.b)
			So(err, ShouldBeNil)
			So(tpw.b.String(), ShouldEqual, "prg1prg2")
			So(NoOutput(), ShouldBeTrue)
		})

		Convey("A Path writer can report error during writing", func() {
			SetBuffers(nil)
			tpw.b = bytes.NewBuffer(nil)
			tw := &testWriter{w: tpw.b}
			err := tpw.WritePath(prgs, tw)
			So(err.Error(), ShouldEqual, "Error writing 'prg2'")
			So(tpw.b.String(), ShouldEqual, "prg1")
			So(NoOutput(), ShouldBeTrue)
		})
	})
}
<|endoftext|>


<commit_before>// +build !pool_sanitize

package pbytes

import (
	"crypto/rand"
	"reflect"
	"testing"
	"unsafe"
)

func TestPoolGet(t *testing.T) {
	for _, test := range []struct {
		min      int
		max      int
		len      int
		cap      int
		exactCap int
	}{
		{
			min:      0,
			max:      64,
			len:      10,
			cap:      24,
			exactCap: 32,
		},
		{
			min:      0,
			max:      0,
			len:      10,
			cap:      24,
			exactCap: 24,
		},
	} {
		t.Run("", func(t *testing.T) {
			p := New(test.min, test.max)
			act := p.Get(test.len, test.cap)
			if n := len(act); n != test.len {
				t.Errorf(
					"Get(%d, _) retured %d-len slice; want %[1]d",
					test.len, n,
				)
			}
			if c := cap(act); c < test.cap {
				t.Errorf(
					"Get(_, %d) retured %d-cap slice; want at least %[1]d",
					test.cap, c,
				)
			}
			if c := cap(act); test.exactCap != 0 && c != test.exactCap {
				t.Errorf(
					"Get(_, %d) retured %d-cap slice; want exact %d",
					test.cap, c, test.exactCap,
				)
			}
		})
	}
}

func TestPoolPut(t *testing.T) {
	p := New(0, 32)

	miss := make([]byte, 5, 5)
	rand.Read(miss)
	p.Put(miss) // Should not reuse.

	hit := make([]byte, 8, 8)
	rand.Read(hit)
	p.Put(hit) // Should reuse.

	b := p.GetLen(5)
	if data(b) == data(miss) {
		t.Fatalf("unexpected reuse")
	}
	if data(b) != data(hit) {
		t.Fatalf("want reuse")
	}
}

func data(p []byte) uintptr {
	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&p))
	return hdr.Data
}
<commit_msg>pbytes: benchmark for lower bound of default pool<commit_after>// +build !pool_sanitize

package pbytes

import (
	"crypto/rand"
	"reflect"
	"strconv"
	"testing"
	"unsafe"
)

func TestPoolGet(t *testing.T) {
	for _, test := range []struct {
		min      int
		max      int
		len      int
		cap      int
		exactCap int
	}{
		{
			min:      0,
			max:      64,
			len:      10,
			cap:      24,
			exactCap: 32,
		},
		{
			min:      0,
			max:      0,
			len:      10,
			cap:      24,
			exactCap: 24,
		},
	} {
		t.Run("", func(t *testing.T) {
			p := New(test.min, test.max)
			act := p.Get(test.len, test.cap)
			if n := len(act); n != test.len {
				t.Errorf(
					"Get(%d, _) retured %d-len slice; want %[1]d",
					test.len, n,
				)
			}
			if c := cap(act); c < test.cap {
				t.Errorf(
					"Get(_, %d) retured %d-cap slice; want at least %[1]d",
					test.cap, c,
				)
			}
			if c := cap(act); test.exactCap != 0 && c != test.exactCap {
				t.Errorf(
					"Get(_, %d) retured %d-cap slice; want exact %d",
					test.cap, c, test.exactCap,
				)
			}
		})
	}
}

func TestPoolPut(t *testing.T) {
	p := New(0, 32)

	miss := make([]byte, 5, 5)
	rand.Read(miss)
	p.Put(miss) // Should not reuse.

	hit := make([]byte, 8, 8)
	rand.Read(hit)
	p.Put(hit) // Should reuse.

	b := p.GetLen(5)
	if data(b) == data(miss) {
		t.Fatalf("unexpected reuse")
	}
	if data(b) != data(hit) {
		t.Fatalf("want reuse")
	}
}

func data(p []byte) uintptr {
	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&p))
	return hdr.Data
}

func BenchmarkPool(b *testing.B) {
	for _, size := range []int{
		1 << 4,
		1 << 5,
		1 << 6,
		1 << 7,
		1 << 8,
		1 << 9,
	} {
		b.Run(strconv.Itoa(size)+"(pool)", func(b *testing.B) {
			b.RunParallel(func(pb *testing.PB) {
				for pb.Next() {
					p := GetLen(size)
					Put(p)
				}
			})
		})
		b.Run(strconv.Itoa(size)+"(make)", func(b *testing.B) {
			b.RunParallel(func(pb *testing.PB) {
				for pb.Next() {
					_ = make([]byte, size)
				}
			})
		})
	}
}
<|endoftext|>