func NewCredentialAuthority(log logger.Logger, api UserKeyAPIer) *CredentialAuthority {
	return newCredentialAuthorityWithEngine(log, api, newStandardEngine())
}
NewCredentialAuthority makes a new signleton CredentialAuthority an start it running. It takes as input
a logger and an API for making keybase API calls
package auth
import (
	"fmt"
	libkb "github.com/keybase/client/go/libkb"
	logger "github.com/keybase/client/go/logger"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	context "golang.org/x/net/context"
	"time"
)
const (
	userTimeout  = 5 * time.Minute
	cacheTimeout = 8 * time.Minute
)
type CredentialAuthority struct {
	log           logger.Logger
	api           UserKeyAPIer
	invalidateCh  chan keybase1.UID
	checkCh       chan checkArg
	shutdownCh    chan struct{}
	cleanItemCh   chan cleanItem
	users         map[keybase1.UID](*userWrapper)
	cleanSchedule []cleanItem
	eng           engine
}
type checkArg struct {
	uid      keybase1.UID
	username *libkb.NormalizedUsername
	kid      *keybase1.KID
	sibkeys  []keybase1.KID
	subkeys  []keybase1.KID
	retCh    chan error
}
func (ca checkArg) String() string {
	return fmt.Sprintf("{uid: %s, username: %s, kid: %s, sibkeys: %v, subkeys: %v}",
		ca.uid, ca.username, ca.kid, ca.sibkeys, ca.subkeys)
}
type userWrapper struct {
	u     *user
	atime time.Time
}
func (uw userWrapper) String() string {
	return fmt.Sprintf("{user: %s, atime: %s}", uw.u, uw.atime)
}
type cleanItem struct {
	uid   keybase1.UID
	ctime time.Time
}
func (ci cleanItem) String() string {
	return fmt.Sprintf("{uid: %s, ctime: %s}", ci.uid, ci.ctime)
}
type user struct {
	uid      keybase1.UID
	username libkb.NormalizedUsername
	sibkeys  map[keybase1.KID]struct{}
	subkeys  map[keybase1.KID]struct{}
	isOK     bool
	ctime    time.Time
	ca       *CredentialAuthority
	checkCh  chan checkArg
	stopCh   chan struct{}
}
func (u user) String() string {
	return fmt.Sprintf("{uid: %s, username: %s, sibkeys: %v, subkeys: %v, isOK: %v, ctime: %s}",
		u.uid, u.username, u.sibkeys, u.subkeys, u.isOK, u.ctime)
}
func newUser(uid keybase1.UID, ca *CredentialAuthority) *user {
	ca.log.Debug("newUser, uid %s", uid)
	ret := &user{
		uid:     uid,
		sibkeys: make(map[keybase1.KID]struct{}),
		subkeys: make(map[keybase1.KID]struct{}),
		ca:      ca,
		checkCh: make(chan checkArg),
		stopCh:  make(chan struct{}),
	}
	go ret.run()
	return ret
}
type UserKeyAPIer interface {
	GetUser(context.Context, keybase1.UID) (
		un libkb.NormalizedUsername, sibkeys, subkeys []keybase1.KID, err error)
	PollForChanges(context.Context) ([]keybase1.UID, error)
}
type engine interface {
	Now() time.Time              
	Evicted(uid keybase1.UID)    
	GetPokeCh() <-chan struct{}  
}
type standardEngine struct {
	pokeCh <-chan struct{}
}
func (se *standardEngine) Now() time.Time { return time.Now() }
func (se *standardEngine) Evicted(uid keybase1.UID) {}
func (se *standardEngine) GetPokeCh() <-chan struct{} { return se.pokeCh }
func newStandardEngine() engine {
	return &standardEngine{
		pokeCh: make(chan struct{}),
	}
}