<commit_before>package gdm

import "net"
import "fmt"
import "strings"
import "time"
import "strconv"
import "errors"

const GDM_PORT_PLAYER = 32412
const GDM_PORT_SERVER = 32414
const SERVER_WAIT_TIME time.Duration = 2

func GetPlayers() ([]*GDMMessage, error) {
    return getter(GDM_PORT_PLAYER)
}

func GetPlayer(name string) (*GDMMessage, error) {
    gdms, err := getter(GDM_PORT_PLAYER)
    if err != nil {
        return nil, err
    }
    for _, gdm := range gdms {
        if (gdm.Props["Name"] == name) || (gdm.Address.IP.String() == name) {
            return gdm, nil
        }
    }
    return nil, errors.New(fmt.Sprintf("No player found named `%s`", name))
}

func GetServers() ([]*GDMMessage, error) {
    return getter(GDM_PORT_SERVER)
}

func GetServer(name string) (*GDMMessage, error) {
    gdms, err := getter(GDM_PORT_SERVER)
    if err != nil {
        return nil, err
    }
    for _, gdm := range gdms {
        if (gdm.Props["Name"] == name) || (gdm.Address.IP.String() == name) {
            return gdm, nil
        }
    }
    return nil, errors.New(fmt.Sprintf("No player found named `%s`", name))
}

func WatchPlayers(freq int) (*GDMWatcher, error) {
    gdms, err := watcher(GDM_PORT_PLAYER, freq)
    if err != nil {
        return nil, err
    }
    return gdms, nil
}

func WatchServers(freq int) (*GDMWatcher, error) {
    gdms, err := watcher(GDM_PORT_SERVER, freq)
    if err != nil {
        return nil, err
    }
    return gdms, nil
}

func WatchForUpdates() {}

type GDMMessage struct {
    Address *net.UDPAddr
    Added bool
    Props map[string]string
}

type GDMWatcher struct {
    Watch chan *GDMMessage
    closer chan bool
}

type gdmBrowser struct {
    mc chan *GDMMessage
    ticker *time.Ticker
    conn *net.UDPConn
}

func (w *GDMWatcher) Close() {
    w.closer <- true
}

func getter(port int) ([]*GDMMessage, error) {
    items := make([]*GDMMessage, 0)
    browser, err := setupBrowser(10)
    if err != nil { return nil, nil }
    browser.listen()
    browser.browse(port)

    timer := time.NewTimer(time.Second * SERVER_WAIT_TIME)
    done := false
    for !done {
        select {
        case <-timer.C:
            done = true
            browser.conn.Close()
        case msg := <- browser.mc:
            items = append(items, msg)
        }
    }
    return items, nil
}

func watcher(port int, freq int) (*GDMWatcher, error) {
    browser, err := setupBrowser(10)
    if err != nil {
        return nil, err
    }
    browser.listen()
    browser.browse(port)
    go func() {
        for {
            <-browser.ticker.C
            browser.browse(port)
        }
    }()

    watcher := &GDMWatcher{Watch: browser.mc, closer: make(chan bool)}
    browser.closer(watcher.closer)

    return watcher, nil
}

func setupBrowser(i int) (*gdmBrowser, error) {
    refresh := (time.Duration(i) * time.Second)
    // setup listener to broadcast stuff
    udpaddr, err := net.ResolveUDPAddr("udp4", ":0")
    if err != nil {
        return nil, err
    }
    conn, lerr := net.ListenUDP("udp4", udpaddr)
    if lerr != nil {
        return nil, lerr
    }
    return &gdmBrowser{conn: conn,
                       mc: make(chan *GDMMessage),
                       ticker: time.NewTicker(refresh)}, nil
}

func (b *gdmBrowser) listen() {
    go func() {
        buf := make([]byte, 1024)
        for {
            mlen, raddr, err := b.conn.ReadFromUDP(buf)
            if err != nil {
                if nerr, ok := err.(net.Error); !ok || !nerr.Temporary() {
                    // this connection has become useless
                    close(b.mc)
                    return
            }
                continue
            }
            msg := string(buf[0:mlen])
            if strings.HasPrefix(msg, "HTTP/1.0 200 OK") {
                gdmmsg := newGDMMessage(msg, raddr)
                b.mc <- gdmmsg
            }
        }
    }()
}

func (b *gdmBrowser) closer(s chan bool) {
    go func() {
        select {
        case <- s:
            b.conn.Close()
            fmt.Println("channel closed")
            return
        }
    }()
}

func (b *gdmBrowser) browse(port int) {
    addrs := getBroadcastAddrs()
    ports := strconv.Itoa(port)
    for _, a := range addrs {
        udpdest, err := net.ResolveUDPAddr("udp4", a+":"+ports)
       if err != nil {
            continue
        }
        buf := []byte("M-SEARCH * HTTP/1.1\r\n\r\n")
        _, werr := b.conn.WriteToUDP(buf, udpdest);
        if werr != nil {
            continue
        }
    }
}

func newGDMMessage(data string, addr *net.UDPAddr) (*GDMMessage) {
    msglines := strings.Split(data, "\r\n")
    gdm := GDMMessage{Address: addr, Added: true, Props: make(map[string]string)}
    for _, m := range msglines {
        if strings.Contains(m, ":") {
            kv := strings.Split(m, ":")
            if len(kv) == 2 {
                gdm.Props[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
            }
        }
    }
    return &gdm
}

func getBroadcastAddrs() (baddr []string) {
    ifaces, _ := net.Interfaces()
    for _, iface := range ifaces {
        // only send on interfaces that are up and can do broadcast
        upandbcast := net.FlagBroadcast | net.FlagUp
        if iface.Flags & upandbcast != upandbcast {
            continue
        }
        addrs, _ := iface.Addrs()
        if len(addrs) == 0 {
            continue
        }
        for _, addr := range addrs {
            var bcast []string
            ip, ipn, err := net.ParseCIDR(addr.String())
            if err != nil {
                continue
            }
            // we only handle ipv4 addresses for now
            ipv4 := ip.To4()
            if ipv4 == nil {
                continue
            }
            for i, m := range ipn.Mask {
                if m == 0 {
                    bcast = append(bcast, "255")
                } else {
                    bcast = append(bcast, fmt.Sprintf("%d", ipv4[i]))
                }
            }
            baddr = append(baddr, strings.Join(bcast, "."))
        }
    }
    return baddr
}
<commit_msg>take out the debug prints, oops<commit_after>package gdm

import "net"
import "fmt"
import "strings"
import "time"
import "strconv"
import "errors"

const GDM_PORT_PLAYER = 32412
const GDM_PORT_SERVER = 32414
const SERVER_WAIT_TIME time.Duration = 2

func GetPlayers() ([]*GDMMessage, error) {
    return getter(GDM_PORT_PLAYER)
}

func GetPlayer(name string) (*GDMMessage, error) {
    gdms, err := getter(GDM_PORT_PLAYER)
    if err != nil {
        return nil, err
    }
    for _, gdm := range gdms {
        if (gdm.Props["Name"] == name) || (gdm.Address.IP.String() == name) {
            return gdm, nil
        }
    }
    return nil, errors.New(fmt.Sprintf("No player found named `%s`", name))
}

func GetServers() ([]*GDMMessage, error) {
    return getter(GDM_PORT_SERVER)
}

func GetServer(name string) (*GDMMessage, error) {
    gdms, err := getter(GDM_PORT_SERVER)
    if err != nil {
        return nil, err
    }
    for _, gdm := range gdms {
        if (gdm.Props["Name"] == name) || (gdm.Address.IP.String() == name) {
            return gdm, nil
        }
    }
    return nil, errors.New(fmt.Sprintf("No player found named `%s`", name))
}

func WatchPlayers(freq int) (*GDMWatcher, error) {
    gdms, err := watcher(GDM_PORT_PLAYER, freq)
    if err != nil {
        return nil, err
    }
    return gdms, nil
}

func WatchServers(freq int) (*GDMWatcher, error) {
    gdms, err := watcher(GDM_PORT_SERVER, freq)
    if err != nil {
        return nil, err
    }
    return gdms, nil
}

func WatchForUpdates() {}

type GDMMessage struct {
    Address *net.UDPAddr
    Added bool
    Props map[string]string
}

type GDMWatcher struct {
    Watch chan *GDMMessage
    closer chan bool
}

type gdmBrowser struct {
    mc chan *GDMMessage
    ticker *time.Ticker
    conn *net.UDPConn
}

func (w *GDMWatcher) Close() {
    w.closer <- true
}

func getter(port int) ([]*GDMMessage, error) {
    items := make([]*GDMMessage, 0)
    browser, err := setupBrowser(10)
    if err != nil { return nil, nil }
    browser.listen()
    browser.browse(port)

    timer := time.NewTimer(time.Second * SERVER_WAIT_TIME)
    done := false
    for !done {
        select {
        case <-timer.C:
            done = true
            browser.conn.Close()
        case msg := <- browser.mc:
            items = append(items, msg)
        }
    }
    return items, nil
}

func watcher(port int, freq int) (*GDMWatcher, error) {
    browser, err := setupBrowser(10)
    if err != nil {
        return nil, err
    }
    browser.listen()
    browser.browse(port)
    go func() {
        for {
            <-browser.ticker.C
            browser.browse(port)
        }
    }()

    watcher := &GDMWatcher{Watch: browser.mc, closer: make(chan bool)}
    browser.closer(watcher.closer)

    return watcher, nil
}

func setupBrowser(i int) (*gdmBrowser, error) {
    refresh := (time.Duration(i) * time.Second)
    // setup listener to broadcast stuff
    udpaddr, err := net.ResolveUDPAddr("udp4", ":0")
    if err != nil {
        return nil, err
    }
    conn, lerr := net.ListenUDP("udp4", udpaddr)
    if lerr != nil {
        return nil, lerr
    }
    return &gdmBrowser{conn: conn,
                       mc: make(chan *GDMMessage),
                       ticker: time.NewTicker(refresh)}, nil
}

func (b *gdmBrowser) listen() {
    go func() {
        buf := make([]byte, 1024)
        for {
            mlen, raddr, err := b.conn.ReadFromUDP(buf)
            if err != nil {
                if nerr, ok := err.(net.Error); !ok || !nerr.Temporary() {
                    // this connection has become useless
                    close(b.mc)
                    return
            }
                continue
            }
            msg := string(buf[0:mlen])
            if strings.HasPrefix(msg, "HTTP/1.0 200 OK") {
                gdmmsg := newGDMMessage(msg, raddr)
                b.mc <- gdmmsg
            }
        }
    }()
}

func (b *gdmBrowser) closer(s chan bool) {
    go func() {
        select {
        case <- s:
            b.conn.Close()
            return
        }
    }()
}

func (b *gdmBrowser) browse(port int) {
    addrs := getBroadcastAddrs()
    ports := strconv.Itoa(port)
    for _, a := range addrs {
        udpdest, err := net.ResolveUDPAddr("udp4", a+":"+ports)
       if err != nil {
            continue
        }
        buf := []byte("M-SEARCH * HTTP/1.1\r\n\r\n")
        _, werr := b.conn.WriteToUDP(buf, udpdest);
        if werr != nil {
            continue
        }
    }
}

func newGDMMessage(data string, addr *net.UDPAddr) (*GDMMessage) {
    msglines := strings.Split(data, "\r\n")
    gdm := GDMMessage{Address: addr, Added: true, Props: make(map[string]string)}
    for _, m := range msglines {
        if strings.Contains(m, ":") {
            kv := strings.Split(m, ":")
            if len(kv) == 2 {
                gdm.Props[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
            }
        }
    }
    return &gdm
}

func getBroadcastAddrs() (baddr []string) {
    ifaces, _ := net.Interfaces()
    for _, iface := range ifaces {
        // only send on interfaces that are up and can do broadcast
        upandbcast := net.FlagBroadcast | net.FlagUp
        if iface.Flags & upandbcast != upandbcast {
            continue
        }
        addrs, _ := iface.Addrs()
        if len(addrs) == 0 {
            continue
        }
        for _, addr := range addrs {
            var bcast []string
            ip, ipn, err := net.ParseCIDR(addr.String())
            if err != nil {
                continue
            }
            // we only handle ipv4 addresses for now
            ipv4 := ip.To4()
            if ipv4 == nil {
                continue
            }
            for i, m := range ipn.Mask {
                if m == 0 {
                    bcast = append(bcast, "255")
                } else {
                    bcast = append(bcast, fmt.Sprintf("%d", ipv4[i]))
                }
            }
            baddr = append(baddr, strings.Join(bcast, "."))
        }
    }
    return baddr
}
<|endoftext|>


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

package runtime

import "unsafe"

// adjust Gobuf as if it executed a call to fn with context ctxt
// and then did an immediate Gosave.
func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
	if buf.lr != 0 {
		throw("invalid use of gostartcall")
	}
	buf.lr = buf.pc
	buf.pc = uintptr(fn)
	buf.ctxt = ctxt
}

// Called to rewind context saved during morestack back to beginning of function.
// To help us, the linker emits a jmp back to the beginning 8 bytes after the
// call to morestack. We just have to decode and apply that jump.
func rewindmorestack(buf *gobuf) {
	var inst uint32
	if buf.pc&3 == 0 && buf.pc != 0 {
		inst = *(*uint32)(unsafe.Pointer(buf.pc + 8))
		// Extract annul, condition, and opcode.
		iacond_op2 := inst >> 22
		// branch always
		mcond := 8 << 25
		// branch on integer condition with prediction
		mop2 := 1 << 22
		// ba,pt
		bapt := uint32((mcond | mop2) >> 22)

		if iacond_op2 == bapt {
			// Extract pc-relative address (4*sign_ext(disp19))
			idisp19 := 4 * (int32(inst<<13) >> 13)
			//ipc := uintptr(unsafe.Pointer(buf.pc))
			buf.pc += 8 + uintptr(idisp19)
			//print("runtime: rewind pc=", hex(ipc), " to pc=", hex(buf.pc), "\n");
			return
		}
	}
	print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
	throw("runtime: misuse of rewindmorestack")
}

func usleep2(us uint32)

//go:linkname usleep1_go runtime.usleep1
//go:nosplit
func usleep1_go(µs uint32) {
	_g_ := getg()

	// Check the validity of m because we might be called in cgo callback
	// path early enough where there isn't a m available yet.
	if _g_ != nil && _g_.m != nil {
		sysvicall1(&libc_usleep, uintptr(µs))
		return
	}
	usleep2(µs)
}
<commit_msg>runtime: account for prologue padding<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

// adjust Gobuf as if it executed a call to fn with context ctxt
// and then did an immediate Gosave.
func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
	if buf.lr != 0 {
		throw("invalid use of gostartcall")
	}
	buf.lr = buf.pc
	buf.pc = uintptr(fn)
	buf.ctxt = ctxt
}

// Called to rewind context saved during morestack back to beginning of function.
// To help us, the linker emits a jmp back to the beginning 8 bytes after the
// call to morestack. We just have to decode and apply that jump.
func rewindmorestack(buf *gobuf) {
	var inst uint32
	if buf.pc&3 == 0 && buf.pc != 0 {
		inst = *(*uint32)(unsafe.Pointer(buf.pc + 8))
		// Extract annul, condition, and opcode.
		iacond_op2 := inst >> 22
		// branch always
		mcond := 8 << 25
		// branch on integer condition with prediction
		mop2 := 1 << 22
		// ba,pt
		bapt := uint32((mcond | mop2) >> 22)

		if iacond_op2 == bapt {
			// Extract pc-relative address (4*sign_ext(disp19))
			idisp19 := 4 * (int32(inst<<13) >> 13)
			//ipc := uintptr(unsafe.Pointer(buf.pc))
			// TODO(shawn): this should include the 8 bytes
			// after the call to morestack, but due to the
			// prologue we pad functions with currently,
			// runtime.gogo assumes all jump points are offset
			// by 8, so we do not add it here.
			buf.pc += uintptr(idisp19)
			//print("runtime: rewind pc=", hex(ipc), " to pc=", hex(buf.pc), "\n");
			return
		}
	}
	print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
	throw("runtime: misuse of rewindmorestack")
}

func usleep2(us uint32)

//go:linkname usleep1_go runtime.usleep1
//go:nosplit
func usleep1_go(µs uint32) {
	_g_ := getg()

	// Check the validity of m because we might be called in cgo callback
	// path early enough where there isn't a m available yet.
	if _g_ != nil && _g_.m != nil {
		sysvicall1(&libc_usleep, uintptr(µs))
		return
	}
	usleep2(µs)
}
<|endoftext|>


<commit_before>package jwt

import (
	"crypto/rsa"
	"errors"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"

	"bytes"

	"github.com/dgrijalva/jwt-go"
	"github.com/mholt/caddy/caddyhttp/httpserver"
)

type JWTAuthBackend interface {
	GetHMACSecret() (b []byte)
	GetRSAPublicKey() (r *rsa.PublicKey)
	IsConfigValid() (v bool)
}

func (h JWTAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	// if the request path is any of the configured paths, validate JWT
	for _, p := range h.Rules {
		if !httpserver.Path(r.URL.Path).Matches(p.Path) {
			continue
		}

		// Check excepted paths for this rule and allow access without validating any token
		var isExceptedPath bool
		for _, e := range p.ExceptedPaths {
			if httpserver.Path(r.URL.Path).Matches(e) {
				isExceptedPath = true
			}
		}
		if isExceptedPath {
			continue
		}
		if r.URL.Path == "/" && p.AllowRoot {
			// special case for protecting children of the root path, only allow access to base directory with directive `allowbase`
			continue
		}

		// Path matches, look for unvalidated token
		uToken, err := ExtractToken(r)
		if err != nil {
			return handleUnauthorized(w, r, p, h.Realm), nil
		}

		backend := backend{}
		// Validate token
		vToken, err := ValidateToken(uToken, backend)
		if err != nil {
			return handleUnauthorized(w, r, p, h.Realm), nil
		}
		vClaims, err := Flatten(vToken.Claims.(jwt.MapClaims), "", DotStyle)
		if err != nil {
			return handleUnauthorized(w, r, p, h.Realm), nil
		}

		// If token contains rules with allow or deny, evaluate
		if len(p.AccessRules) > 0 {
			var isAuthorized []bool
			for _, rule := range p.AccessRules {
				v := vClaims[rule.Claim]
				ruleMatches := contains(v, rule.Value) || v == rule.Value
				switch rule.Authorize {
				case ALLOW:
					isAuthorized = append(isAuthorized, ruleMatches)
				case DENY:
					isAuthorized = append(isAuthorized, !ruleMatches)
				default:
					return handleUnauthorized(w, r, p, h.Realm), fmt.Errorf("unknown rule type")
				}
			}
			// test all flags, if any are true then ok to pass
			ok := false
			for _, result := range isAuthorized {
				if result {
					ok = true
				}
			}
			if !ok {
				return handleForbidden(w, r, p, h.Realm), nil
			}
		}

		// set claims as separate headers for downstream to consume
		for claim, value := range vClaims {
			headerName := "Token-Claim-" + strings.ToUpper(claim)
			switch v := value.(type) {
			case string:
				r.Header.Set(headerName, v)
			case int64:
				r.Header.Set(headerName, strconv.FormatInt(v, 10))
			case bool:
				r.Header.Set(headerName, strconv.FormatBool(v))
			case int32:
				r.Header.Set(headerName, strconv.FormatInt(int64(v), 10))
			case float32:
				r.Header.Set(headerName, strconv.FormatFloat(float64(v), 'f', -1, 32))
			case float64:
				r.Header.Set(headerName, strconv.FormatFloat(v, 'f', -1, 64))
			case []interface{}:
				b := bytes.NewBufferString("")
				for i, item := range v {
					if i > 0 {
						b.WriteString(",")
					}
					b.WriteString(fmt.Sprintf("%v", item))
				}
				r.Header.Set(headerName, b.String())
			default:
				// ignore, because, JWT spec says in https://tools.ietf.org/html/rfc7519#section-4
				//     all claims that are not understood
				//     by implementations MUST be ignored.
			}
		}

		return h.Next.ServeHTTP(w, r)
	}
	// pass request if no paths protected with JWT
	return h.Next.ServeHTTP(w, r)
}

// ExtractToken will find a JWT token passed one of three ways: (1) as the Authorization
// header in the form `Bearer <JWT Token>`; (2) as a cookie named `jwt_token`; (3) as
// a URL query paramter of the form https://example.com?token=<JWT token>
func ExtractToken(r *http.Request) (string, error) {
	jwtHeader := strings.Split(r.Header.Get("Authorization"), " ")
	if jwtHeader[0] == "Bearer" && len(jwtHeader) == 2 {
		return jwtHeader[1], nil
	}

	jwtCookie, err := r.Cookie("jwt_token")
	if err == nil {
		return jwtCookie.Value, nil
	}

	jwtQuery := r.URL.Query().Get("token")
	if jwtQuery != "" {
		return jwtQuery, nil
	}

	return "", fmt.Errorf("no token found")
}

// ValidateToken will return a parsed token if it passes validation, or an
// error if any part of the token fails validation.  Possible errors include
// malformed tokens, unknown/unspecified signing algorithms, missing secret key,
// tokens that are not valid yet (i.e., 'nbf' field), tokens that are expired,
// and tokens that fail signature verification (forged)
func ValidateToken(uToken string, b JWTAuthBackend) (*jwt.Token, error) {
	if len(uToken) == 0 {
		return nil, fmt.Errorf("Token length is zero")
	}

	if !b.IsConfigValid() {
		return nil, errors.New("No valid configuration for JWT validation found")
	}

	hmac := b.GetHMACSecret()
	rsa := b.GetRSAPublicKey()

	switch {
	case hmac != nil:
		token, err := jwt.Parse(uToken, func(t *jwt.Token) (interface{}, error) {
			if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("HMAC: Unexpected signing method: %v", t.Header["alg"])
			}
			return hmac, nil
		})

		if err != nil {
			return nil, err
		}

		return token, nil

	case rsa != nil:
		token, err := jwt.Parse(uToken, func(t *jwt.Token) (interface{}, error) {
			if _, ok := t.Method.(*jwt.SigningMethodRSA); !ok {
				return nil, fmt.Errorf("RSA: Unexpected signing method: %v", t.Header["alg"])
			}
			return rsa, nil
		})
		if err != nil {
			return nil, err
		}

		return token, nil
	default:
		return nil, errors.New("No valid configuration for JWT validation found")
	}

}

type backend struct{}

// JWT signing token must be set as environment variable JWT_SECRET and not
// be the empty string
func (b backend) GetHMACSecret() []byte {
	secret := os.Getenv("JWT_SECRET")
	if secret == "" {
		return nil
	}
	return []byte(secret)
}

func (b backend) GetRSAPublicKey() *rsa.PublicKey {
	pem := os.Getenv("JWT_PUBLIC_KEY")
	if pem == "" {
		return nil
	}
	rsaPub, err := jwt.ParseRSAPublicKeyFromPEM([]byte(pem))
	if err != nil {
		return nil
	}
	return rsaPub
}

func (b backend) IsConfigValid() bool {

	hmac := b.GetHMACSecret()
	rsa := b.GetRSAPublicKey()

	switch {
	case hmac != nil && rsa == nil:
		return true
	case hmac == nil && rsa != nil:
		return true
	default:
		return false
	}
}

// handleUnauthorized checks, which action should be performed if access was denied.
// It returns the status code and writes the Location header in case of a redirect.
// Possible caddy variables in the location value will be substituted.
func handleUnauthorized(w http.ResponseWriter, r *http.Request, rule Rule, realm string) int {
	if rule.Redirect != "" {
		replacer := httpserver.NewReplacer(r, nil, "")
		http.Redirect(w, r, replacer.Replace(rule.Redirect), http.StatusSeeOther)
		return http.StatusSeeOther
	}

	w.Header().Add("WWW-Authenticate", fmt.Sprintf("Bearer realm=\"%s\",error=\"invalid_token\"", realm))
	return http.StatusUnauthorized
}

// handleForbidden checks, which action should be performed if access was denied.
// It returns the status code and writes the Location header in case of a redirect.
// Possible caddy variables in the location value will be substituted.
func handleForbidden(w http.ResponseWriter, r *http.Request, rule Rule, realm string) int {
	if rule.Redirect != "" {
		replacer := httpserver.NewReplacer(r, nil, "")
		http.Redirect(w, r, replacer.Replace(rule.Redirect), http.StatusSeeOther)
		return http.StatusSeeOther
	}
	w.Header().Add("WWW-Authenticate", fmt.Sprintf("Bearer realm=\"%s\",error=\"insufficient_scope\"", realm))
	return http.StatusForbidden
}

// contains checks weather list is a slice ans containts the
// supplied string value.
func contains(list interface{}, value string) bool {
	switch l := list.(type) {
	case []interface{}:
		for _, v := range l {
			if v == value {
				return true
			}
		}
	}
	return false
}
<commit_msg>allow exceptions to paths that should be unprotected. Fixes #23<commit_after>package jwt

import (
	"crypto/rsa"
	"errors"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"

	"bytes"

	"github.com/dgrijalva/jwt-go"
	"github.com/mholt/caddy/caddyhttp/httpserver"
)

// JWTAuthBackend represents a backend interface that retrieves secret key material
// to validate tokens
type JWTAuthBackend interface {
	GetHMACSecret() (b []byte)
	GetRSAPublicKey() (r *rsa.PublicKey)
	IsConfigValid() (v bool)
}

func (h JWTAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	// if the request path is any of the configured paths, validate JWT
	for _, p := range h.Rules {
		if !httpserver.Path(r.URL.Path).Matches(p.Path) {
			continue
		}

		// Check excepted paths for this rule and allow access without validating any token
		var isExceptedPath bool
		for _, e := range p.ExceptedPaths {
			if httpserver.Path(r.URL.Path).Matches(e) {
				isExceptedPath = true
			}
		}
		if isExceptedPath {
			continue
		}
		if r.URL.Path == "/" && p.AllowRoot {
			// special case for protecting children of the root path, only allow access to base directory with directive `allowbase`
			continue
		}

		// Path matches, look for unvalidated token
		uToken, err := ExtractToken(r)
		if err != nil {
			return handleUnauthorized(w, r, p, h.Realm), nil
		}

		backend := backend{}
		// Validate token
		vToken, err := ValidateToken(uToken, backend)
		if err != nil {
			return handleUnauthorized(w, r, p, h.Realm), nil
		}
		vClaims, err := Flatten(vToken.Claims.(jwt.MapClaims), "", DotStyle)
		if err != nil {
			return handleUnauthorized(w, r, p, h.Realm), nil
		}

		// If token contains rules with allow or deny, evaluate
		if len(p.AccessRules) > 0 {
			var isAuthorized []bool
			for _, rule := range p.AccessRules {
				v := vClaims[rule.Claim]
				ruleMatches := contains(v, rule.Value) || v == rule.Value
				switch rule.Authorize {
				case ALLOW:
					isAuthorized = append(isAuthorized, ruleMatches)
				case DENY:
					isAuthorized = append(isAuthorized, !ruleMatches)
				default:
					return handleUnauthorized(w, r, p, h.Realm), fmt.Errorf("unknown rule type")
				}
			}
			// test all flags, if any are true then ok to pass
			ok := false
			for _, result := range isAuthorized {
				if result {
					ok = true
				}
			}
			if !ok {
				return handleForbidden(w, r, p, h.Realm), nil
			}
		}

		// set claims as separate headers for downstream to consume
		for claim, value := range vClaims {
			headerName := "Token-Claim-" + strings.ToUpper(claim)
			switch v := value.(type) {
			case string:
				r.Header.Set(headerName, v)
			case int64:
				r.Header.Set(headerName, strconv.FormatInt(v, 10))
			case bool:
				r.Header.Set(headerName, strconv.FormatBool(v))
			case int32:
				r.Header.Set(headerName, strconv.FormatInt(int64(v), 10))
			case float32:
				r.Header.Set(headerName, strconv.FormatFloat(float64(v), 'f', -1, 32))
			case float64:
				r.Header.Set(headerName, strconv.FormatFloat(v, 'f', -1, 64))
			case []interface{}:
				b := bytes.NewBufferString("")
				for i, item := range v {
					if i > 0 {
						b.WriteString(",")
					}
					b.WriteString(fmt.Sprintf("%v", item))
				}
				r.Header.Set(headerName, b.String())
			default:
				// ignore, because, JWT spec says in https://tools.ietf.org/html/rfc7519#section-4
				//     all claims that are not understood
				//     by implementations MUST be ignored.
			}
		}

		return h.Next.ServeHTTP(w, r)
	}
	// pass request if no paths protected with JWT
	return h.Next.ServeHTTP(w, r)
}

// ExtractToken will find a JWT token passed one of three ways: (1) as the Authorization
// header in the form `Bearer <JWT Token>`; (2) as a cookie named `jwt_token`; (3) as
// a URL query paramter of the form https://example.com?token=<JWT token>
func ExtractToken(r *http.Request) (string, error) {
	jwtHeader := strings.Split(r.Header.Get("Authorization"), " ")
	if jwtHeader[0] == "Bearer" && len(jwtHeader) == 2 {
		return jwtHeader[1], nil
	}

	jwtCookie, err := r.Cookie("jwt_token")
	if err == nil {
		return jwtCookie.Value, nil
	}

	jwtQuery := r.URL.Query().Get("token")
	if jwtQuery != "" {
		return jwtQuery, nil
	}

	return "", fmt.Errorf("no token found")
}

// ValidateToken will return a parsed token if it passes validation, or an
// error if any part of the token fails validation.  Possible errors include
// malformed tokens, unknown/unspecified signing algorithms, missing secret key,
// tokens that are not valid yet (i.e., 'nbf' field), tokens that are expired,
// and tokens that fail signature verification (forged)
func ValidateToken(uToken string, b JWTAuthBackend) (*jwt.Token, error) {
	if len(uToken) == 0 {
		return nil, fmt.Errorf("Token length is zero")
	}

	if !b.IsConfigValid() {
		return nil, errors.New("No valid configuration for JWT validation found")
	}

	hmac := b.GetHMACSecret()
	rsa := b.GetRSAPublicKey()

	switch {
	case hmac != nil:
		token, err := jwt.Parse(uToken, func(t *jwt.Token) (interface{}, error) {
			if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("HMAC: Unexpected signing method: %v", t.Header["alg"])
			}
			return hmac, nil
		})

		if err != nil {
			return nil, err
		}

		return token, nil

	case rsa != nil:
		token, err := jwt.Parse(uToken, func(t *jwt.Token) (interface{}, error) {
			if _, ok := t.Method.(*jwt.SigningMethodRSA); !ok {
				return nil, fmt.Errorf("RSA: Unexpected signing method: %v", t.Header["alg"])
			}
			return rsa, nil
		})
		if err != nil {
			return nil, err
		}

		return token, nil
	default:
		return nil, errors.New("No valid configuration for JWT validation found")
	}

}

type backend struct{}

// JWT signing token must be set as environment variable JWT_SECRET and not
// be the empty string
func (b backend) GetHMACSecret() []byte {
	secret := os.Getenv("JWT_SECRET")
	if secret == "" {
		return nil
	}
	return []byte(secret)
}

func (b backend) GetRSAPublicKey() *rsa.PublicKey {
	pem := os.Getenv("JWT_PUBLIC_KEY")
	if pem == "" {
		return nil
	}
	rsaPub, err := jwt.ParseRSAPublicKeyFromPEM([]byte(pem))
	if err != nil {
		return nil
	}
	return rsaPub
}

func (b backend) IsConfigValid() bool {

	hmac := b.GetHMACSecret()
	rsa := b.GetRSAPublicKey()

	switch {
	case hmac != nil && rsa == nil:
		return true
	case hmac == nil && rsa != nil:
		return true
	default:
		return false
	}
}

// handleUnauthorized checks, which action should be performed if access was denied.
// It returns the status code and writes the Location header in case of a redirect.
// Possible caddy variables in the location value will be substituted.
func handleUnauthorized(w http.ResponseWriter, r *http.Request, rule Rule, realm string) int {
	if rule.Redirect != "" {
		replacer := httpserver.NewReplacer(r, nil, "")
		http.Redirect(w, r, replacer.Replace(rule.Redirect), http.StatusSeeOther)
		return http.StatusSeeOther
	}

	w.Header().Add("WWW-Authenticate", fmt.Sprintf("Bearer realm=\"%s\",error=\"invalid_token\"", realm))
	return http.StatusUnauthorized
}

// handleForbidden checks, which action should be performed if access was denied.
// It returns the status code and writes the Location header in case of a redirect.
// Possible caddy variables in the location value will be substituted.
func handleForbidden(w http.ResponseWriter, r *http.Request, rule Rule, realm string) int {
	if rule.Redirect != "" {
		replacer := httpserver.NewReplacer(r, nil, "")
		http.Redirect(w, r, replacer.Replace(rule.Redirect), http.StatusSeeOther)
		return http.StatusSeeOther
	}
	w.Header().Add("WWW-Authenticate", fmt.Sprintf("Bearer realm=\"%s\",error=\"insufficient_scope\"", realm))
	return http.StatusForbidden
}

// contains checks weather list is a slice ans containts the
// supplied string value.
func contains(list interface{}, value string) bool {
	switch l := list.(type) {
	case []interface{}:
		for _, v := range l {
			if v == value {
				return true
			}
		}
	}
	return false
}
<|endoftext|>


<commit_before>package jwt

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"net/http"
	"strings"
	"time"
)

// TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time).
// You can override it to use another time value.  This is useful for testing or if your
// server uses a different time zone than your tokens.
var TimeFunc = time.Now

// Parse methods use this callback function to supply
// the key for verification.  The function receives the parsed,
// but unverified Token.  This allows you to use propries in the
// Header of the token (such as `kid`) to identify which key to use.
type Keyfunc func(*Token) ([]byte, error)

// A JWT Token
type Token struct {
	Raw    string
	Header map[string]interface{}
	Claims map[string]interface{}
	Method SigningMethod
	// This is only populated when you Parse a token
	Signature string
	// This is only populated when you Parse/Verify a token
	Valid bool
}

func New(method SigningMethod) *Token {
	return &Token{
		Header: map[string]interface{}{
			"typ": "JWT",
			"alg": method.Alg(),
		},
		Claims: make(map[string]interface{}),
		Method: method,
	}
}

// Get the complete, signed token
func (t *Token) SignedString(key []byte) (string, error) {
	var sig, sstr string
	var err error
	if sstr, err = t.SigningString(); err != nil {
		return "", err
	}
	if sig, err = t.Method.Sign(sstr, key); err != nil {
		return "", err
	}
	return strings.Join([]string{sstr, sig}, "."), nil
}

// Generate the signing string.  This is the
// most expensive part of the whole deal.  Unless you
// need this for something special, just go straight for
// the SignedString.
func (t *Token) SigningString() (string, error) {
	var err error
	parts := make([]string, 2)
	for i, _ := range parts {
		var source map[string]interface{}
		if i == 0 {
			source = t.Header
		} else {
			source = t.Claims
		}

		var jsonValue []byte
		if jsonValue, err = json.Marshal(source); err != nil {
			return "", err
		}

		parts[i] = EncodeSegment(jsonValue)
	}
	return strings.Join(parts, "."), nil
}

// Parse, validate, and return a token.
// keyFunc will receive the parsed token and should return the key for validating.
// If everything is kosher, err will be nil
func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
	parts := strings.Split(tokenString, ".")
	if len(parts) == 3 {
		var err error
		token := &Token{Raw: tokenString}
		// parse Header
		var headerBytes []byte
		if headerBytes, err = DecodeSegment(parts[0]); err != nil {
			return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
		}
		if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
			return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
		}

		// parse Claims
		var claimBytes []byte
		if claimBytes, err = DecodeSegment(parts[1]); err != nil {
			return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
		}
		if err = json.Unmarshal(claimBytes, &token.Claims); err != nil {
			return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
		}

		// Lookup signature method
		if method, ok := token.Header["alg"].(string); ok {
			if token.Method = GetSigningMethod(method); token.Method == nil {
				return token, &ValidationError{err: "Signing method (alg) is unavailable.", Errors: ValidationErrorUnverifiable}
			}
		} else {
			return token, &ValidationError{err: "Signing method (alg) is unspecified.", Errors: ValidationErrorUnverifiable}
		}

		// Lookup key
		var key []byte
		if key, err = keyFunc(token); err != nil {
			return token, &ValidationError{err: err.Error(), Errors: ValidationErrorUnverifiable}
		}

		// Check expiration times
		vErr := &ValidationError{}
		now := TimeFunc().Unix()
		if exp, ok := token.Claims["exp"].(float64); ok {
			if now > int64(exp) {
				vErr.err = "Token is expired"
				vErr.Errors |= ValidationErrorExpired
			}
		}
		if nbf, ok := token.Claims["nbf"].(float64); ok {
			if now < int64(nbf) {
				vErr.err = "Token is not valid yet"
				vErr.Errors |= ValidationErrorNotValidYet
			}
		}

		// Perform validation
		if err = token.Method.Verify(strings.Join(parts[0:2], "."), parts[2], key); err != nil {
			vErr.err = err.Error()
			vErr.Errors |= ValidationErrorSignatureInvalid
		}

		if vErr.valid() {
			token.Valid = true
			return token, nil
		}

		return token, vErr

	} else {
		return nil, &ValidationError{err: "Token contains an invalid number of segments", Errors: ValidationErrorMalformed}
	}
}

const (
	ValidationErrorMalformed        uint32 = 1 << iota // Token is malformed
	ValidationErrorUnverifiable                        // Token could not be verified because of signing problems
	ValidationErrorSignatureInvalid                    // Signature validation failed
	ValidationErrorExpired                             // Exp validation failed
	ValidationErrorNotValidYet                         // NBF validation failed
)

// The error from Parse if token is not valid
type ValidationError struct {
	err    string
	Errors uint32 // bitfield.  see ValidationError... constants
}

// Validation error is an error type
func (e *ValidationError) Error() string {
	if e.err == "" {
		return "Token is invalid"
	}
	return e.err
}

// No errors
func (e *ValidationError) valid() bool {
	if e.Errors > 0 {
		return false
	}
	return true
}

// Try to find the token in an http.Request.
// This method will call ParseMultipartForm if there's no token in the header.
// Currently, it looks in the Authorization header as well as
// looking for an 'access_token' request parameter in req.Form.
func ParseFromRequest(req *http.Request, keyFunc Keyfunc) (token *Token, err error) {

	// Look for an Authorization header
	if ah := req.Header.Get("Authorization"); ah != "" {
		// Should be a bearer token
		if len(ah) > 6 && strings.ToUpper(ah[0:6]) == "BEARER" {
			return Parse(ah[7:], keyFunc)
		}
	}

	// Look for "access_token" parameter
	req.ParseMultipartForm(10e6)
	if tokStr := req.Form.Get("access_token"); tokStr != "" {
		return Parse(tokStr, keyFunc)
	}

	return nil, errors.New("No token present in request.")

}

// Encode JWT specific base64url encoding with padding stripped
func EncodeSegment(seg []byte) string {
	return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=")
}

// Decode JWT specific base64url encoding with padding stripped
func DecodeSegment(seg string) ([]byte, error) {
	// len % 4
	switch len(seg) % 4 {
	case 2:
		seg = seg + "=="
	case 3:
		seg = seg + "==="
	}

	return base64.URLEncoding.DecodeString(seg)
}
<commit_msg>documentation<commit_after>package jwt

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"net/http"
	"strings"
	"time"
)

// TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time).
// You can override it to use another time value.  This is useful for testing or if your
// server uses a different time zone than your tokens.
var TimeFunc = time.Now

// Parse methods use this callback function to supply
// the key for verification.  The function receives the parsed,
// but unverified Token.  This allows you to use propries in the
// Header of the token (such as `kid`) to identify which key to use.
type Keyfunc func(*Token) ([]byte, error)

// A JWT Token
type Token struct {
	Raw    string
	Header map[string]interface{}
	Claims map[string]interface{}
	Method SigningMethod
	// This is only populated when you Parse a token
	Signature string
	// This is only populated when you Parse/Verify a token
	Valid bool
}

func New(method SigningMethod) *Token {
	return &Token{
		Header: map[string]interface{}{
			"typ": "JWT",
			"alg": method.Alg(),
		},
		Claims: make(map[string]interface{}),
		Method: method,
	}
}

// Get the complete, signed token
func (t *Token) SignedString(key []byte) (string, error) {
	var sig, sstr string
	var err error
	if sstr, err = t.SigningString(); err != nil {
		return "", err
	}
	if sig, err = t.Method.Sign(sstr, key); err != nil {
		return "", err
	}
	return strings.Join([]string{sstr, sig}, "."), nil
}

// Generate the signing string.  This is the
// most expensive part of the whole deal.  Unless you
// need this for something special, just go straight for
// the SignedString.
func (t *Token) SigningString() (string, error) {
	var err error
	parts := make([]string, 2)
	for i, _ := range parts {
		var source map[string]interface{}
		if i == 0 {
			source = t.Header
		} else {
			source = t.Claims
		}

		var jsonValue []byte
		if jsonValue, err = json.Marshal(source); err != nil {
			return "", err
		}

		parts[i] = EncodeSegment(jsonValue)
	}
	return strings.Join(parts, "."), nil
}

// Parse, validate, and return a token.
// keyFunc will receive the parsed token and should return the key for validating.
// If everything is kosher, err will be nil
func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
	parts := strings.Split(tokenString, ".")
	if len(parts) == 3 {
		var err error
		token := &Token{Raw: tokenString}
		// parse Header
		var headerBytes []byte
		if headerBytes, err = DecodeSegment(parts[0]); err != nil {
			return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
		}
		if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
			return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
		}

		// parse Claims
		var claimBytes []byte
		if claimBytes, err = DecodeSegment(parts[1]); err != nil {
			return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
		}
		if err = json.Unmarshal(claimBytes, &token.Claims); err != nil {
			return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
		}

		// Lookup signature method
		if method, ok := token.Header["alg"].(string); ok {
			if token.Method = GetSigningMethod(method); token.Method == nil {
				return token, &ValidationError{err: "Signing method (alg) is unavailable.", Errors: ValidationErrorUnverifiable}
			}
		} else {
			return token, &ValidationError{err: "Signing method (alg) is unspecified.", Errors: ValidationErrorUnverifiable}
		}

		// Lookup key
		var key []byte
		if key, err = keyFunc(token); err != nil {
			return token, &ValidationError{err: err.Error(), Errors: ValidationErrorUnverifiable}
		}

		// Check expiration times
		vErr := &ValidationError{}
		now := TimeFunc().Unix()
		if exp, ok := token.Claims["exp"].(float64); ok {
			if now > int64(exp) {
				vErr.err = "Token is expired"
				vErr.Errors |= ValidationErrorExpired
			}
		}
		if nbf, ok := token.Claims["nbf"].(float64); ok {
			if now < int64(nbf) {
				vErr.err = "Token is not valid yet"
				vErr.Errors |= ValidationErrorNotValidYet
			}
		}

		// Perform validation
		if err = token.Method.Verify(strings.Join(parts[0:2], "."), parts[2], key); err != nil {
			vErr.err = err.Error()
			vErr.Errors |= ValidationErrorSignatureInvalid
		}

		if vErr.valid() {
			token.Valid = true
			return token, nil
		}

		return token, vErr

	} else {
		return nil, &ValidationError{err: "Token contains an invalid number of segments", Errors: ValidationErrorMalformed}
	}
}

// The errors that might occur when parsing and validating a token
const (
	ValidationErrorMalformed        uint32 = 1 << iota // Token is malformed
	ValidationErrorUnverifiable                        // Token could not be verified because of signing problems
	ValidationErrorSignatureInvalid                    // Signature validation failed
	ValidationErrorExpired                             // Exp validation failed
	ValidationErrorNotValidYet                         // NBF validation failed
)

// The error from Parse if token is not valid
type ValidationError struct {
	err    string
	Errors uint32 // bitfield.  see ValidationError... constants
}

// Validation error is an error type
func (e *ValidationError) Error() string {
	if e.err == "" {
		return "Token is invalid"
	}
	return e.err
}

// No errors
func (e *ValidationError) valid() bool {
	if e.Errors > 0 {
		return false
	}
	return true
}

// Try to find the token in an http.Request.
// This method will call ParseMultipartForm if there's no token in the header.
// Currently, it looks in the Authorization header as well as
// looking for an 'access_token' request parameter in req.Form.
func ParseFromRequest(req *http.Request, keyFunc Keyfunc) (token *Token, err error) {

	// Look for an Authorization header
	if ah := req.Header.Get("Authorization"); ah != "" {
		// Should be a bearer token
		if len(ah) > 6 && strings.ToUpper(ah[0:6]) == "BEARER" {
			return Parse(ah[7:], keyFunc)
		}
	}

	// Look for "access_token" parameter
	req.ParseMultipartForm(10e6)
	if tokStr := req.Form.Get("access_token"); tokStr != "" {
		return Parse(tokStr, keyFunc)
	}

	return nil, errors.New("No token present in request.")

}

// Encode JWT specific base64url encoding with padding stripped
func EncodeSegment(seg []byte) string {
	return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=")
}

// Decode JWT specific base64url encoding with padding stripped
func DecodeSegment(seg string) ([]byte, error) {
	// len % 4
	switch len(seg) % 4 {
	case 2:
		seg = seg + "=="
	case 3:
		seg = seg + "==="
	}

	return base64.URLEncoding.DecodeString(seg)
}
<|endoftext|>


<commit_before>package jwt

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"net/http"
	"strings"
	"time"
)

// TimeFunc is used when parsing token to validate "exp" claim (expiration time).
// You can override it to use another time zone (UTC for example).
var TimeFunc = time.Now

// Parse methods use this callback function to supply
// the key for verification.  The function receives the parsed,
// but unverified Token.  This allows you to use propries in the
// Header of the token (such as `kid`) to identify which key to use.
type Keyfunc func(*Token) ([]byte, error)

// A JWT Token
type Token struct {
	Raw    string
	Header map[string]interface{}
	Claims map[string]interface{}
	Method SigningMethod
	// This is only populated when you Parse a token
	Signature string
	// This is only populated when you Parse/Verify a token
	Valid bool
}

func New(method SigningMethod) *Token {
	return &Token{
		Header: map[string]interface{}{
			"typ": "JWT",
			"alg": method.Alg(),
		},
		Claims: make(map[string]interface{}),
		Method: method,
	}
}

// Get the complete, signed token
func (t *Token) SignedString(key []byte) (string, error) {
	var sig, sstr string
	var err error
	if sstr, err = t.SigningString(); err != nil {
		return "", err
	}
	if sig, err = t.Method.Sign(sstr, key); err != nil {
		return "", err
	}
	return strings.Join([]string{sstr, sig}, "."), nil
}

// Generate the signing string.  This is the
// most expensive part of the whole deal.  Unless you
// need this for something special, just go straight for
// the SignedString.
func (t *Token) SigningString() (string, error) {
	var err error
	parts := make([]string, 2)
	for i, _ := range parts {
		var source map[string]interface{}
		if i == 0 {
			source = t.Header
		} else {
			source = t.Claims
		}

		var jsonValue []byte
		if jsonValue, err = json.Marshal(source); err != nil {
			return "", err
		}

		parts[i] = EncodeSegment(jsonValue)
	}
	return strings.Join(parts, "."), nil
}

// Parse, validate, and return a token.
// keyFunc will receive the parsed token and should return the key for validating.
// If everything is kosher, err will be nil
func Parse(tokenString string, keyFunc Keyfunc) (token *Token, err error) {
	parts := strings.Split(tokenString, ".")
	if len(parts) == 3 {
		token = &Token{Raw: tokenString}
		// parse Header
		var headerBytes []byte
		if headerBytes, err = DecodeSegment(parts[0]); err != nil {
			return
		}
		if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
			return
		}

		// parse Claims
		var claimBytes []byte
		if claimBytes, err = DecodeSegment(parts[1]); err != nil {
			return
		}
		if err = json.Unmarshal(claimBytes, &token.Claims); err != nil {
			return
		}

		// Lookup signature method
		if method, ok := token.Header["alg"].(string); ok {
			if token.Method = GetSigningMethod(method); token.Method == nil {
				err = errors.New("Signing method (alg) is unavailable.")
				return
			}
		} else {
			err = errors.New("Signing method (alg) is unspecified.")
			return
		}

		// Check expiry times
		if exp, ok := token.Claims["exp"].(float64); ok {
			if TimeFunc().Unix() > int64(exp) {
				err = errors.New("Token is expired")
			}
		}

		// Lookup key
		var key []byte
		if key, err = keyFunc(token); err != nil {
			return
		}

		// Perform validation
		if err = token.Method.Verify(strings.Join(parts[0:2], "."), parts[2], key); err == nil {
			token.Valid = true
		}

	} else {
		err = errors.New("Token contains an invalid number of segments")
	}
	return
}

// Try to find the token in an http.Request.
// This method will call ParseMultipartForm if there's no token in the header.
// Currently, it looks in the Authorization header as well as
// looking for an 'access_token' request parameter in req.Form.
func ParseFromRequest(req *http.Request, keyFunc Keyfunc) (token *Token, err error) {

	// Look for an Authorization header
	if ah := req.Header.Get("Authorization"); ah != "" {
		// Should be a bearer token
		if len(ah) > 6 && strings.ToUpper(ah[0:6]) == "BEARER" {
			return Parse(ah[7:], keyFunc)
		}
	}

	// Look for "access_token" parameter
	req.ParseMultipartForm(10e6)
	if tokStr := req.Form.Get("access_token"); tokStr != "" {
		return Parse(tokStr, keyFunc)
	}

	return nil, errors.New("No token present in request.")

}

// Encode JWT specific base64url encoding with padding stripped
func EncodeSegment(seg []byte) string {
	return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=")
}

// Decode JWT specific base64url encoding with padding stripped
func DecodeSegment(seg string) ([]byte, error) {
	// len % 4
	switch len(seg) % 4 {
	case 2:
		seg = seg + "=="
	case 3:
		seg = seg + "==="
	}

	return base64.URLEncoding.DecodeString(seg)
}
<commit_msg>updated TimeFunc documentation<commit_after>package jwt

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"net/http"
	"strings"
	"time"
)

// TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time).
// You can override it to use another time value.  This is useful for testing or if your
// server uses a different time zone than your tokens.
var TimeFunc = time.Now

// Parse methods use this callback function to supply
// the key for verification.  The function receives the parsed,
// but unverified Token.  This allows you to use propries in the
// Header of the token (such as `kid`) to identify which key to use.
type Keyfunc func(*Token) ([]byte, error)

// A JWT Token
type Token struct {
	Raw    string
	Header map[string]interface{}
	Claims map[string]interface{}
	Method SigningMethod
	// This is only populated when you Parse a token
	Signature string
	// This is only populated when you Parse/Verify a token
	Valid bool
}

func New(method SigningMethod) *Token {
	return &Token{
		Header: map[string]interface{}{
			"typ": "JWT",
			"alg": method.Alg(),
		},
		Claims: make(map[string]interface{}),
		Method: method,
	}
}

// Get the complete, signed token
func (t *Token) SignedString(key []byte) (string, error) {
	var sig, sstr string
	var err error
	if sstr, err = t.SigningString(); err != nil {
		return "", err
	}
	if sig, err = t.Method.Sign(sstr, key); err != nil {
		return "", err
	}
	return strings.Join([]string{sstr, sig}, "."), nil
}

// Generate the signing string.  This is the
// most expensive part of the whole deal.  Unless you
// need this for something special, just go straight for
// the SignedString.
func (t *Token) SigningString() (string, error) {
	var err error
	parts := make([]string, 2)
	for i, _ := range parts {
		var source map[string]interface{}
		if i == 0 {
			source = t.Header
		} else {
			source = t.Claims
		}

		var jsonValue []byte
		if jsonValue, err = json.Marshal(source); err != nil {
			return "", err
		}

		parts[i] = EncodeSegment(jsonValue)
	}
	return strings.Join(parts, "."), nil
}

// Parse, validate, and return a token.
// keyFunc will receive the parsed token and should return the key for validating.
// If everything is kosher, err will be nil
func Parse(tokenString string, keyFunc Keyfunc) (token *Token, err error) {
	parts := strings.Split(tokenString, ".")
	if len(parts) == 3 {
		token = &Token{Raw: tokenString}
		// parse Header
		var headerBytes []byte
		if headerBytes, err = DecodeSegment(parts[0]); err != nil {
			return
		}
		if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
			return
		}

		// parse Claims
		var claimBytes []byte
		if claimBytes, err = DecodeSegment(parts[1]); err != nil {
			return
		}
		if err = json.Unmarshal(claimBytes, &token.Claims); err != nil {
			return
		}

		// Lookup signature method
		if method, ok := token.Header["alg"].(string); ok {
			if token.Method = GetSigningMethod(method); token.Method == nil {
				err = errors.New("Signing method (alg) is unavailable.")
				return
			}
		} else {
			err = errors.New("Signing method (alg) is unspecified.")
			return
		}

		// Check expiry times
		if exp, ok := token.Claims["exp"].(float64); ok {
			if TimeFunc().Unix() > int64(exp) {
				err = errors.New("Token is expired")
			}
		}

		// Lookup key
		var key []byte
		if key, err = keyFunc(token); err != nil {
			return
		}

		// Perform validation
		if err = token.Method.Verify(strings.Join(parts[0:2], "."), parts[2], key); err == nil {
			token.Valid = true
		}

	} else {
		err = errors.New("Token contains an invalid number of segments")
	}
	return
}

// Try to find the token in an http.Request.
// This method will call ParseMultipartForm if there's no token in the header.
// Currently, it looks in the Authorization header as well as
// looking for an 'access_token' request parameter in req.Form.
func ParseFromRequest(req *http.Request, keyFunc Keyfunc) (token *Token, err error) {

	// Look for an Authorization header
	if ah := req.Header.Get("Authorization"); ah != "" {
		// Should be a bearer token
		if len(ah) > 6 && strings.ToUpper(ah[0:6]) == "BEARER" {
			return Parse(ah[7:], keyFunc)
		}
	}

	// Look for "access_token" parameter
	req.ParseMultipartForm(10e6)
	if tokStr := req.Form.Get("access_token"); tokStr != "" {
		return Parse(tokStr, keyFunc)
	}

	return nil, errors.New("No token present in request.")

}

// Encode JWT specific base64url encoding with padding stripped
func EncodeSegment(seg []byte) string {
	return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=")
}

// Decode JWT specific base64url encoding with padding stripped
func DecodeSegment(seg string) ([]byte, error) {
	// len % 4
	switch len(seg) % 4 {
	case 2:
		seg = seg + "=="
	case 3:
		seg = seg + "==="
	}

	return base64.URLEncoding.DecodeString(seg)
}
<|endoftext|>


<commit_before>package dmgo

type lcd struct {
	framebuffer   []byte
	flipRequested bool // for whateve really draws the fb

	oam [160]byte

	scrollY byte
	scrollX byte
	windowY byte
	windowX byte

	backgroundPaletteReg byte
	objectPalette0Reg    byte
	objectPalette1Reg    byte

	hBlankInterrupt      bool
	vBlankInterrupt      bool
	oamInterrupt         bool
	lycEqualsLyInterrupt bool

	lyReg  byte
	lycReg byte

	inVBlank     bool
	inHBlank     bool
	accessingOAM bool
	readingData  bool

	// control bits
	displayOn                   bool
	useUpperWindowTileMap       bool
	displayWindow               bool
	useLowerBGAndWindowTileData bool
	useUpperBGTileMap           bool
	bigSprites                  bool
	displaySprites              bool
	displayBG                   bool

	cyclesSinceLYInc       uint
	cyclesSinceVBlankStart uint
}

func (lcd *lcd) writeOAM(addr uint16, val byte) {
	// TODO: display mode checks (most disallow writing)
	// TODO: OAM
	lcd.oam[addr] = val
}

// lcd is on at startup
func (lcd *lcd) init() {
	lcd.displayOn = true
	lcd.accessingOAM = true // at start of line
	lcd.framebuffer = make([]byte, 160*144*4)
}

// FIXME: timings will have to change for double-speed mode
// FIXME: also need to actually *do* lcd activies here
// FIXME: will need to pass in mem here once actually drawing
// (maybe instead of counting cycles I'll count actual instruction time?)
// (or maybe it'll always be dmg cycles and gbc will run the fn e.g. twice instead of 4 times)
//
// FIXME: surely better way instead of having
// a "run every cycle" function, would be a
// step function that takes the number of
// cycles as an arg, does lcd += cycles,
// then updates flags accordingly? Would
// cut number of times this fn is run by
// prolly ~8x.
func (lcd *lcd) runCycles(cs *cpuState, ncycles uint) {
	if !lcd.displayOn {
		return
	}

	lcd.cyclesSinceLYInc += ncycles

	if lcd.accessingOAM && lcd.cyclesSinceLYInc >= 80 {
		lcd.accessingOAM = false
		lcd.readingData = true
	}

	if lcd.readingData && lcd.cyclesSinceLYInc >= 252 {
		lcd.readingData = false
		lcd.inHBlank = true

		if lcd.hBlankInterrupt {
			cs.lcdStatIRQ = true
		}
	}

	if lcd.cyclesSinceLYInc >= 456 {
		lcd.renderScanline(cs)

		lcd.cyclesSinceLYInc = 0
		if !lcd.inVBlank {
			lcd.accessingOAM = true
			if lcd.oamInterrupt {
				cs.lcdStatIRQ = true
			}
		}
		lcd.inHBlank = false
		lcd.lyReg++

		if lcd.lycEqualsLyInterrupt {
			if lcd.lyReg == lcd.lycReg {
				cs.lcdStatIRQ = true
			}
		}
	}

	if lcd.lyReg >= 144 && !lcd.inVBlank {
		lcd.inVBlank = true

		cs.vBlankIRQ = true
		if lcd.vBlankInterrupt {
			cs.lcdStatIRQ = true
		}

		lcd.flipRequested = true
	}

	if lcd.inVBlank {
		lcd.cyclesSinceVBlankStart += ncycles
		if lcd.cyclesSinceVBlankStart >= 456*10 {
			lcd.lyReg = 0
			lcd.inVBlank = false
			lcd.accessingOAM = true
			lcd.cyclesSinceVBlankStart = 0

			if lcd.lycEqualsLyInterrupt {
				if lcd.lyReg == lcd.lycReg {
					cs.lcdStatIRQ = true
				}
			}
		}
	}
}

func (cs *cpuState) getTilePixel(tdataAddr uint16, tileNum, x, y byte) byte {
	if tdataAddr == 0x8800 {
		tileNum = byte(int(int8(tileNum)) + 128)
	}
	mapBitY, mapBitX := y&0x07, x&0x07
	dataByteL := cs.read(tdataAddr + uint16(tileNum)*16 + uint16(mapBitY)*2)
	dataByteH := cs.read(tdataAddr + uint16(tileNum)*16 + uint16(mapBitY)*2 + 1)
	dataBitL := (dataByteL >> (7 - mapBitX)) & 0x1
	dataBitH := (dataByteH >> (7 - mapBitX)) & 0x1
	return (dataBitH << 1) | dataBitL
}
func (cs *cpuState) getTileNum(tmapAddr uint16, x, y byte) byte {
	tileNumY, tileNumX := uint16(y>>3), uint16(x>>3)
	tileNum := cs.read(tmapAddr + tileNumY*32 + tileNumX)
	return tileNum
}

func (cs *cpuState) getBGPixel(x, y byte) (byte, byte, byte) {
	mapAddr := cs.lcd.getBGTileMapAddr()
	dataAddr := cs.lcd.getBGAndWindowTileDataAddr()
	tileNum := cs.getTileNum(mapAddr, x, y)
	rawPixel := cs.getTilePixel(dataAddr, tileNum, x, y)
	palettedPixel := (cs.lcd.backgroundPaletteReg >> (rawPixel * 2)) & 0x03
	return cs.applyCustomPalette(palettedPixel)
}

func (cs *cpuState) getWindowPixel(x, y byte) (byte, byte, byte) {
	mapAddr := cs.lcd.getWindowTileMapAddr()
	dataAddr := cs.lcd.getBGAndWindowTileDataAddr()
	tileNum := cs.getTileNum(mapAddr, x, y)
	rawPixel := cs.getTilePixel(dataAddr, tileNum, x, y)
	palettedPixel := (cs.lcd.backgroundPaletteReg >> (rawPixel * 2)) & 0x03
	return cs.applyCustomPalette(palettedPixel)
}

func (cs *cpuState) getSpritePixel(e *oamEntry, x, y byte) (byte, byte, byte, bool) {
	tileX, tileY := byte(int16(x)-e.x), byte(int16(y)-e.y)
	if e.xFlip() {
		tileX = 7 - tileX
	}
	if e.yFlip() {
		tileY = e.height - 1 - tileY
	}
	tileNum := e.tileNum
	if e.height == 16 {
		tileNum &^= 0x01
		if tileY >= 8 {
			tileNum++
			tileY -= 8
		}
	}
	rawPixel := cs.getTilePixel(0x8000, tileNum, tileX, tileY)
	if rawPixel == 0 {
		return 0, 0, 0, false // transparent
	}
	palReg := cs.lcd.objectPalette0Reg
	if e.palSelector() {
		palReg = cs.lcd.objectPalette1Reg
	}
	palettedPixel := (palReg >> (rawPixel * 2)) & 0x03
	r, g, b := cs.applyCustomPalette(palettedPixel)
	return r, g, b, true
}

func (cs *cpuState) applyCustomPalette(val byte) (byte, byte, byte) {
	// TODO: actual palette choices
	outVal := (0xff / 3) * (3 - val)
	return outVal, outVal, outVal
}

func (lcd *lcd) getBGTileMapAddr() uint16 {
	if lcd.useUpperBGTileMap {
		return 0x9c00
	}
	return 0x9800
}
func (lcd *lcd) getWindowTileMapAddr() uint16 {
	if lcd.useUpperWindowTileMap {
		return 0x9c00
	}
	return 0x9800
}
func (lcd *lcd) getBGAndWindowTileDataAddr() uint16 {
	if lcd.useLowerBGAndWindowTileData {
		return 0x8000
	}
	return 0x8800
}

type oamEntry struct {
	y         int16
	x         int16
	height    byte
	tileNum   byte
	flagsByte byte
}

func (e *oamEntry) behindBG() bool    { return e.flagsByte&0x80 != 0 }
func (e *oamEntry) yFlip() bool       { return e.flagsByte&0x40 != 0 }
func (e *oamEntry) xFlip() bool       { return e.flagsByte&0x20 != 0 }
func (e *oamEntry) palSelector() bool { return e.flagsByte&0x10 != 0 }

func (e *oamEntry) inScanline(yByte byte) bool {
	y := int16(yByte)
	return y >= e.y && y < e.y+int16(e.height)
}
func (e *oamEntry) inX(xByte byte) bool {
	x := int16(xByte)
	return x >= e.x && x < e.x+8
}
func (lcd *lcd) parseOAM() []oamEntry {
	height := 8
	if lcd.bigSprites {
		height = 16
	}
	entries := make([]oamEntry, 40)
	for i := 0; i < 40; i++ {
		addr := i * 4
		entries[i] = oamEntry{
			y:         int16(lcd.oam[addr]) - 16,
			x:         int16(lcd.oam[addr+1]) - 8,
			height:    byte(height),
			tileNum:   lcd.oam[addr+2],
			flagsByte: lcd.oam[addr+3],
		}
	}
	return entries
}

func (lcd *lcd) renderScanline(cs *cpuState) {
	if lcd.lyReg >= 144 {
		return
	}
	lcd.fillScanline(0)

	y := lcd.lyReg

	// for sprite priority
	bgMask := make([]bool, 160)
	maskR, maskG, maskB := cs.applyCustomPalette(0)

	if lcd.displayBG || true {
		bgY := y + lcd.scrollY
		for x := byte(0); x < 160; x++ {
			bgX := x + lcd.scrollX
			r, g, b := cs.getBGPixel(bgX, bgY)
			lcd.setFramebufferPixel(x, y, r, g, b)
			if r == maskR && g == maskG && b == maskB {
				bgMask[x] = true
			}
		}
	}
	if lcd.displayWindow && y >= lcd.windowY {
		winY := y - lcd.windowY
		winStartX := int(lcd.windowX) - 7
		for x := winStartX; x < 160; x++ {
			if x < 0 {
				continue
			}
			r, g, b := cs.getWindowPixel(byte(x-winStartX), winY)
			lcd.setFramebufferPixel(byte(x), y, r, g, b)
			if r == maskR && g == maskG && b == maskB {
				bgMask[x] = true
			}
		}
	}

	if lcd.displaySprites {
		seen := 0
		entries := lcd.parseOAM()
		for x := byte(0); x < 160 && seen < 11; x++ {
			for _, e := range entries {
				if e.inScanline(y) && e.inX(x) {
					if e.x == int16(x) || x == 0 {
						if seen++; seen == 11 {
							break
						}
					}
					if r, g, b, a := cs.getSpritePixel(&e, x, y); a {
						if !e.behindBG() || bgMask[x] {
							lcd.setFramebufferPixel(x, y, r, g, b)
						}
						break
					}
				}
			}
		}
	}
}

func (lcd *lcd) getFramebufferPixel(xByte, yByte byte) (byte, byte, byte) {
	x, y := int(xByte), int(yByte)
	r := lcd.framebuffer[y*160*4+x*4+0]
	g := lcd.framebuffer[y*160*4+x*4+1]
	b := lcd.framebuffer[y*160*4+x*4+2]
	return r, g, b
}
func (lcd *lcd) setFramebufferPixel(xByte, yByte, r, g, b byte) {
	x, y := int(xByte), int(yByte)
	lcd.framebuffer[y*160*4+x*4+0] = r
	lcd.framebuffer[y*160*4+x*4+1] = g
	lcd.framebuffer[y*160*4+x*4+2] = b
	lcd.framebuffer[y*160*4+x*4+3] = 0xff
}
func (lcd *lcd) fillScanline(val byte) {
	y := int(lcd.lyReg)
	for x := 0; x < 160; x++ {
		lcd.framebuffer[y*160*4+x*4+0] = val
		lcd.framebuffer[y*160*4+x*4+1] = val
		lcd.framebuffer[y*160*4+x*4+2] = val
		lcd.framebuffer[y*160*4+x*4+3] = 0xff
	}
}

func (lcd *lcd) writeControlReg(val byte) {
	boolsFromByte(val,
		&lcd.displayOn,
		&lcd.useUpperWindowTileMap,
		&lcd.displayWindow,
		&lcd.useLowerBGAndWindowTileData,
		&lcd.useUpperBGTileMap,
		&lcd.bigSprites,
		&lcd.displaySprites,
		&lcd.displayBG,
	)
}
func (lcd *lcd) readControlReg() byte {
	return byteFromBools(
		lcd.displayOn,
		lcd.useUpperWindowTileMap,
		lcd.displayWindow,
		lcd.useLowerBGAndWindowTileData,
		lcd.useUpperBGTileMap,
		lcd.bigSprites,
		lcd.displaySprites,
		lcd.displayBG,
	)
}

func (lcd *lcd) writeStatusReg(val byte) {
	boolsFromByte(val,
		nil,
		&lcd.lycEqualsLyInterrupt,
		&lcd.oamInterrupt,
		&lcd.vBlankInterrupt,
		&lcd.hBlankInterrupt,
		nil,
		nil,
		nil,
	)
}
func (lcd *lcd) readStatusReg() byte {
	return byteFromBools(
		true, // bit 7 always set
		lcd.lycEqualsLyInterrupt,
		lcd.oamInterrupt,
		lcd.vBlankInterrupt,
		lcd.hBlankInterrupt,
		lcd.lyReg == lcd.lycReg,
		lcd.accessingOAM || lcd.readingData,
		lcd.inVBlank || lcd.readingData,
	)
}
<commit_msg>Some control bits must be buffered til next hblank<commit_after>package dmgo

type lcd struct {
	framebuffer   []byte
	flipRequested bool // for whateve really draws the fb

	oam [160]byte

	scrollY byte
	scrollX byte
	windowY byte
	windowX byte

	backgroundPaletteReg byte
	objectPalette0Reg    byte
	objectPalette1Reg    byte

	hBlankInterrupt      bool
	vBlankInterrupt      bool
	oamInterrupt         bool
	lycEqualsLyInterrupt bool

	lyReg  byte
	lycReg byte

	inVBlank     bool
	inHBlank     bool
	accessingOAM bool
	readingData  bool

	// needs to be here for buf, see runCycles
	pendingDisplayWindow bool

	// control bits
	displayOn                   bool
	useUpperWindowTileMap       bool
	displayWindow               bool
	useLowerBGAndWindowTileData bool
	useUpperBGTileMap           bool
	bigSprites                  bool
	displaySprites              bool
	displayBG                   bool

	cyclesSinceLYInc       uint
	cyclesSinceVBlankStart uint
}

func (lcd *lcd) updateBufferedControlBits() {
	lcd.displayWindow = lcd.pendingDisplayWindow
}

func (lcd *lcd) writeOAM(addr uint16, val byte) {
	// TODO: display mode checks (most disallow writing)
	// TODO: OAM
	lcd.oam[addr] = val
}

// lcd is on at startup
func (lcd *lcd) init() {
	lcd.displayOn = true
	lcd.accessingOAM = true // at start of line
	lcd.framebuffer = make([]byte, 160*144*4)
}

// FIXME: timings will have to change for double-speed mode
// (maybe instead of counting cycles I'll count actual instruction time?)
// (or maybe it'll always be dmg cycles and gbc will run the fn e.g. twice instead of 4 times)
func (lcd *lcd) runCycles(cs *cpuState, ncycles uint) {
	if !lcd.displayOn {
		return
	}

	lcd.cyclesSinceLYInc += ncycles

	if lcd.accessingOAM && lcd.cyclesSinceLYInc >= 80 {
		lcd.accessingOAM = false
		lcd.readingData = true
	}

	if lcd.readingData && lcd.cyclesSinceLYInc >= 252 {
		lcd.readingData = false
		lcd.inHBlank = true

		if lcd.hBlankInterrupt {
			cs.lcdStatIRQ = true
		}
	}

	if lcd.cyclesSinceLYInc >= 456 {

		lcd.renderScanline(cs)

		lcd.cyclesSinceLYInc = 0
		if !lcd.inVBlank {
			lcd.accessingOAM = true
			if lcd.oamInterrupt {
				cs.lcdStatIRQ = true
			}
		}
		lcd.inHBlank = false
		lcd.lyReg++

		// It looks like some internal control bits are only
		// updated at the beginning of each scanline.
		// Putting this here because it looks like a game
		// does something like "ok, ly=lyc for the last
		// line of my window, so lets turn the window off",
		// which would fail to draw that last line if you
		// didn't buffer up those changes until after the
		// hblank.
		lcd.updateBufferedControlBits()

		if lcd.lycEqualsLyInterrupt {
			if lcd.lyReg == lcd.lycReg {
				cs.lcdStatIRQ = true
			}
		}
	}

	if lcd.lyReg >= 144 && !lcd.inVBlank {
		lcd.inVBlank = true

		cs.vBlankIRQ = true
		if lcd.vBlankInterrupt {
			cs.lcdStatIRQ = true
		}

		lcd.flipRequested = true
	}

	if lcd.inVBlank {
		lcd.cyclesSinceVBlankStart += ncycles
		if lcd.cyclesSinceVBlankStart >= 456*10 {
			lcd.lyReg = 0
			lcd.inVBlank = false
			lcd.accessingOAM = true
			lcd.cyclesSinceVBlankStart = 0

			if lcd.lycEqualsLyInterrupt {
				if lcd.lyReg == lcd.lycReg {
					cs.lcdStatIRQ = true
				}
			}
		}
	}
}

func (cs *cpuState) getTilePixel(tdataAddr uint16, tileNum, x, y byte) byte {
	if tdataAddr == 0x8800 {
		tileNum = byte(int(int8(tileNum)) + 128)
	}
	mapBitY, mapBitX := y&0x07, x&0x07
	dataByteL := cs.read(tdataAddr + uint16(tileNum)*16 + uint16(mapBitY)*2)
	dataByteH := cs.read(tdataAddr + uint16(tileNum)*16 + uint16(mapBitY)*2 + 1)
	dataBitL := (dataByteL >> (7 - mapBitX)) & 0x1
	dataBitH := (dataByteH >> (7 - mapBitX)) & 0x1
	return (dataBitH << 1) | dataBitL
}
func (cs *cpuState) getTileNum(tmapAddr uint16, x, y byte) byte {
	tileNumY, tileNumX := uint16(y>>3), uint16(x>>3)
	tileNum := cs.read(tmapAddr + tileNumY*32 + tileNumX)
	return tileNum
}

func (cs *cpuState) getBGPixel(x, y byte) (byte, byte, byte) {
	mapAddr := cs.lcd.getBGTileMapAddr()
	dataAddr := cs.lcd.getBGAndWindowTileDataAddr()
	tileNum := cs.getTileNum(mapAddr, x, y)
	rawPixel := cs.getTilePixel(dataAddr, tileNum, x, y)
	palettedPixel := (cs.lcd.backgroundPaletteReg >> (rawPixel * 2)) & 0x03
	return cs.applyCustomPalette(palettedPixel)
}

func (cs *cpuState) getWindowPixel(x, y byte) (byte, byte, byte) {
	mapAddr := cs.lcd.getWindowTileMapAddr()
	dataAddr := cs.lcd.getBGAndWindowTileDataAddr()
	tileNum := cs.getTileNum(mapAddr, x, y)
	rawPixel := cs.getTilePixel(dataAddr, tileNum, x, y)
	palettedPixel := (cs.lcd.backgroundPaletteReg >> (rawPixel * 2)) & 0x03
	return cs.applyCustomPalette(palettedPixel)
}

func (cs *cpuState) getSpritePixel(e *oamEntry, x, y byte) (byte, byte, byte, bool) {
	tileX, tileY := byte(int16(x)-e.x), byte(int16(y)-e.y)
	if e.xFlip() {
		tileX = 7 - tileX
	}
	if e.yFlip() {
		tileY = e.height - 1 - tileY
	}
	tileNum := e.tileNum
	if e.height == 16 {
		tileNum &^= 0x01
		if tileY >= 8 {
			tileNum++
			tileY -= 8
		}
	}
	rawPixel := cs.getTilePixel(0x8000, tileNum, tileX, tileY)
	if rawPixel == 0 {
		return 0, 0, 0, false // transparent
	}
	palReg := cs.lcd.objectPalette0Reg
	if e.palSelector() {
		palReg = cs.lcd.objectPalette1Reg
	}
	palettedPixel := (palReg >> (rawPixel * 2)) & 0x03
	r, g, b := cs.applyCustomPalette(palettedPixel)
	return r, g, b, true
}

func (cs *cpuState) applyCustomPalette(val byte) (byte, byte, byte) {
	// TODO: actual palette choices
	outVal := (0xff / 3) * (3 - val)
	return outVal, outVal, outVal
}

func (lcd *lcd) getBGTileMapAddr() uint16 {
	if lcd.useUpperBGTileMap {
		return 0x9c00
	}
	return 0x9800
}
func (lcd *lcd) getWindowTileMapAddr() uint16 {
	if lcd.useUpperWindowTileMap {
		return 0x9c00
	}
	return 0x9800
}
func (lcd *lcd) getBGAndWindowTileDataAddr() uint16 {
	if lcd.useLowerBGAndWindowTileData {
		return 0x8000
	}
	return 0x8800
}

type oamEntry struct {
	y         int16
	x         int16
	height    byte
	tileNum   byte
	flagsByte byte
}

func (e *oamEntry) behindBG() bool    { return e.flagsByte&0x80 != 0 }
func (e *oamEntry) yFlip() bool       { return e.flagsByte&0x40 != 0 }
func (e *oamEntry) xFlip() bool       { return e.flagsByte&0x20 != 0 }
func (e *oamEntry) palSelector() bool { return e.flagsByte&0x10 != 0 }

func (e *oamEntry) inScanline(yByte byte) bool {
	y := int16(yByte)
	return y >= e.y && y < e.y+int16(e.height)
}
func (e *oamEntry) inX(xByte byte) bool {
	x := int16(xByte)
	return x >= e.x && x < e.x+8
}
func (lcd *lcd) parseOAM() []oamEntry {
	height := 8
	if lcd.bigSprites {
		height = 16
	}
	entries := make([]oamEntry, 40)
	for i := 0; i < 40; i++ {
		addr := i * 4
		entries[i] = oamEntry{
			y:         int16(lcd.oam[addr]) - 16,
			x:         int16(lcd.oam[addr+1]) - 8,
			height:    byte(height),
			tileNum:   lcd.oam[addr+2],
			flagsByte: lcd.oam[addr+3],
		}
	}
	return entries
}

func (lcd *lcd) renderScanline(cs *cpuState) {
	if lcd.lyReg >= 144 {
		return
	}
	lcd.fillScanline(0)

	y := lcd.lyReg

	// for sprite priority
	bgMask := make([]bool, 160)
	maskR, maskG, maskB := cs.applyCustomPalette(0)

	if lcd.displayBG || true {
		bgY := y + lcd.scrollY
		for x := byte(0); x < 160; x++ {
			bgX := x + lcd.scrollX
			r, g, b := cs.getBGPixel(bgX, bgY)
			lcd.setFramebufferPixel(x, y, r, g, b)
			if r == maskR && g == maskG && b == maskB {
				bgMask[x] = true
			}
		}
	}
	if lcd.displayWindow && y >= lcd.windowY {
		winY := y - lcd.windowY
		winStartX := int(lcd.windowX) - 7
		for x := winStartX; x < 160; x++ {
			if x < 0 {
				continue
			}
			r, g, b := cs.getWindowPixel(byte(x-winStartX), winY)
			lcd.setFramebufferPixel(byte(x), y, r, g, b)
			if r == maskR && g == maskG && b == maskB {
				bgMask[x] = true
			}
		}
	}

	if lcd.displaySprites {
		seen := 0
		entries := lcd.parseOAM()
		for x := byte(0); x < 160 && seen < 11; x++ {
			for _, e := range entries {
				if e.inScanline(y) && e.inX(x) {
					if e.x == int16(x) || x == 0 {
						if seen++; seen == 11 {
							break
						}
					}
					if r, g, b, a := cs.getSpritePixel(&e, x, y); a {
						if !e.behindBG() || bgMask[x] {
							lcd.setFramebufferPixel(x, y, r, g, b)
						}
						break
					}
				}
			}
		}
	}
}

func (lcd *lcd) getFramebufferPixel(xByte, yByte byte) (byte, byte, byte) {
	x, y := int(xByte), int(yByte)
	r := lcd.framebuffer[y*160*4+x*4+0]
	g := lcd.framebuffer[y*160*4+x*4+1]
	b := lcd.framebuffer[y*160*4+x*4+2]
	return r, g, b
}
func (lcd *lcd) setFramebufferPixel(xByte, yByte, r, g, b byte) {
	x, y := int(xByte), int(yByte)
	lcd.framebuffer[y*160*4+x*4+0] = r
	lcd.framebuffer[y*160*4+x*4+1] = g
	lcd.framebuffer[y*160*4+x*4+2] = b
	lcd.framebuffer[y*160*4+x*4+3] = 0xff
}
func (lcd *lcd) fillScanline(val byte) {
	y := int(lcd.lyReg)
	for x := 0; x < 160; x++ {
		lcd.framebuffer[y*160*4+x*4+0] = val
		lcd.framebuffer[y*160*4+x*4+1] = val
		lcd.framebuffer[y*160*4+x*4+2] = val
		lcd.framebuffer[y*160*4+x*4+3] = 0xff
	}
}

func (lcd *lcd) writeControlReg(val byte) {
	boolsFromByte(val,
		&lcd.displayOn,
		&lcd.useUpperWindowTileMap,
		&lcd.pendingDisplayWindow,
		&lcd.useLowerBGAndWindowTileData,
		&lcd.useUpperBGTileMap,
		&lcd.bigSprites,
		&lcd.displaySprites,
		&lcd.displayBG,
	)
}
func (lcd *lcd) readControlReg() byte {
	return byteFromBools(
		lcd.displayOn,
		lcd.useUpperWindowTileMap,
		lcd.pendingDisplayWindow,
		lcd.useLowerBGAndWindowTileData,
		lcd.useUpperBGTileMap,
		lcd.bigSprites,
		lcd.displaySprites,
		lcd.displayBG,
	)
}

func (lcd *lcd) writeStatusReg(val byte) {
	boolsFromByte(val,
		nil,
		&lcd.lycEqualsLyInterrupt,
		&lcd.oamInterrupt,
		&lcd.vBlankInterrupt,
		&lcd.hBlankInterrupt,
		nil,
		nil,
		nil,
	)
}
func (lcd *lcd) readStatusReg() byte {
	return byteFromBools(
		true, // bit 7 always set
		lcd.lycEqualsLyInterrupt,
		lcd.oamInterrupt,
		lcd.vBlankInterrupt,
		lcd.hBlankInterrupt,
		lcd.lyReg == lcd.lycReg,
		lcd.accessingOAM || lcd.readingData,
		lcd.inVBlank || lcd.readingData,
	)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/kidoman/embd"
	_ "github.com/kidoman/embd/host/all"
	"os"
	"strings"
	"time"
	//"github.com/stianeikeland/go-rpio"
)

// var (
// 	ledRed = rpio.Pin(4)
// 	ledYellow = rpio.Pin(17)
// 	ledGreen = rpio.Pin(27)
// )

var (
	ledRed, _    = embd.NewDigitalPin(7)
	ledYellow, _ = embd.NewDigitalPin(0)
	ledGreen, _  = embd.NewDigitalPin(2)
)

func getLEDString(color string) string {
	return "Toggle " + strings.ToUpper(color)
}

func getToggledValue(pin embd.DigitalPin) int {
	val,_ := pin.Read()
	if val == embd.High {
		return embd.Low
	} else {
		return embd.High
	}
}

func toggleLED(pin embd.DigitalPin, color string) {
	fmt.Println(getLEDString(color))
	toggledValue := getToggledValue(pin)
	fmt.Println("Val to write", toggledValue)
	embd.DigitalWrite(pin.N(), embd.High)
	// err := pin.Write(toggledValue)
	// if err != nil {
 // 		fmt.Println(err)
 // 		os.Exit(1)
	// }
}

// func toggleLED(pin rpio.Pin, color string)  {
// 	fmt.Println(getLEDString(color))
// 	pin.Toggle()
// }

func initLEDs() {
	embd.SetDirection(4, embd.Out)
	embd.SetDirection(17, embd.Out)
	embd.SetDirection(27, embd.Out)
	// ledRed.Output()
	// ledYellow.Output()
	// ledGreen.Output()
}

func main() {
	fmt.Println("Parsing parameters")
	num := flag.Int("num", 0, "number of blinks")
	flag.Parse()

	fmt.Println("Number of blinks:", *num)

	fmt.Println("Opening rpio access")

	//var err = rpio.Open()
	embd.InitGPIO()

	// if err != nil {
	// 	fmt.Println(err)
	// 	os.Exit(1)
	// }

	//defer rpio.Close()
	defer embd.CloseGPIO()

	fmt.Println("Pin as output")

	for i := 0; i < *num; i++ {
		if i%3 == 0 {
			toggleLED(ledRed, "red")
		} else if i%3 == 1 {
			toggleLED(ledYellow, "yellow")
		} else {
			toggleLED(ledGreen, "green")
		}
		time.Sleep(time.Second)
	}
}
<commit_msg>Remove unused import<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/kidoman/embd"
	_ "github.com/kidoman/embd/host/all"
	//"os"
	"strings"
	"time"
	//"github.com/stianeikeland/go-rpio"
)

// var (
// 	ledRed = rpio.Pin(4)
// 	ledYellow = rpio.Pin(17)
// 	ledGreen = rpio.Pin(27)
// )

var (
	ledRed, _    = embd.NewDigitalPin(7)
	ledYellow, _ = embd.NewDigitalPin(0)
	ledGreen, _  = embd.NewDigitalPin(2)
)

func getLEDString(color string) string {
	return "Toggle " + strings.ToUpper(color)
}

func getToggledValue(pin embd.DigitalPin) int {
	val,_ := pin.Read()
	if val == embd.High {
		return embd.Low
	} else {
		return embd.High
	}
}

func toggleLED(pin embd.DigitalPin, color string) {
	fmt.Println(getLEDString(color))
	toggledValue := getToggledValue(pin)
	fmt.Println("Val to write", toggledValue)
	embd.DigitalWrite(pin.N(), embd.High)
	// err := pin.Write(toggledValue)
	// if err != nil {
 // 		fmt.Println(err)
 // 		os.Exit(1)
	// }
}

// func toggleLED(pin rpio.Pin, color string)  {
// 	fmt.Println(getLEDString(color))
// 	pin.Toggle()
// }

func initLEDs() {
	embd.SetDirection(4, embd.Out)
	embd.SetDirection(17, embd.Out)
	embd.SetDirection(27, embd.Out)
	// ledRed.Output()
	// ledYellow.Output()
	// ledGreen.Output()
}

func main() {
	fmt.Println("Parsing parameters")
	num := flag.Int("num", 0, "number of blinks")
	flag.Parse()

	fmt.Println("Number of blinks:", *num)

	fmt.Println("Opening rpio access")

	//var err = rpio.Open()
	embd.InitGPIO()

	// if err != nil {
	// 	fmt.Println(err)
	// 	os.Exit(1)
	// }

	//defer rpio.Close()
	defer embd.CloseGPIO()

	fmt.Println("Pin as output")

	for i := 0; i < *num; i++ {
		if i%3 == 0 {
			toggleLED(ledRed, "red")
		} else if i%3 == 1 {
			toggleLED(ledYellow, "yellow")
		} else {
			toggleLED(ledGreen, "green")
		}
		time.Sleep(time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	flags "github.com/jessevdk/go-flags"
	"github.com/mit-dci/lit/coinparam"
	"github.com/mit-dci/lit/litbamf"
	"github.com/mit-dci/lit/litrpc"
	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/qln"
)

type config struct { // define a struct for usage with go-flags
	Tn3host     string `long:"tn3" description:"Connect to bitcoin testnet3."`
	Bc2host     string `long:"bc2" description:"bc2 full node."`
	Lt4host     string `long:"lt4" description:"Connect to litecoin testnet4."`
	Reghost     string `long:"reg" description:"Connect to bitcoin regtest."`
	Litereghost string `long:"litereg" description:"Connect to litecoin regtest."`
	Tvtchost    string `long:"tvtc" description:"Connect to Vertcoin test node."`
	Vtchost     string `long:"vtc" description:"Connect to Vertcoin."`
	LitHomeDir  string `long:"dir" description:"Specify Home Directory of lit as an absolute path."`
	TrackerURL  string `long:"tracker" description:"LN address tracker URL http|https://host:port"`
	ConfigFile  string

	ReSync  bool `short:"r" long:"reSync" description:"Resync from the given tip."`
	Tower   bool `long:"tower" description:"Watchtower: Run a watching node"`
	Hard    bool `short:"t" long:"hard" description:"Flag to set networks."`
	Verbose bool `short:"v" long:"verbose" description:"Set verbosity to true."`

	Rpcport uint16 `short:"p" long:"rpcport" description:"Set RPC port to connect to"`

	Params *coinparam.Params
}

var (
	defaultLitHomeDirName = os.Getenv("HOME") + "/.lit"
	defaultTrackerURL     = "http://ni.media.mit.edu:46580"
	defaultKeyFileName    = "privkey.hex"
	defaultConfigFilename = "lit.conf"
	defaultHomeDir        = os.Getenv("HOME")
	defaultConfigFile     = filepath.Join(os.Getenv("HOME"), "/.lit/lit.conf")
	defaultRpcport        = uint16(8001)
)

func fileExists(name string) bool {
	if _, err := os.Stat(name); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

// newConfigParser returns a new command line flags parser.
func newConfigParser(conf *config, options flags.Options) *flags.Parser {
	parser := flags.NewParser(conf, options)
	return parser
}
func linkWallets(node *qln.LitNode, key *[32]byte, conf *config) error {
	// for now, wallets are linked to the litnode on startup, and
	// can't appear / disappear while it's running.  Later
	// could support dynamically adding / removing wallets

	// order matters; the first registered wallet becomes the default

	var err error
	// try regtest
	if conf.Reghost != "" {
		p := &coinparam.RegressionNetParams
		fmt.Printf("reg: %s\n", conf.Reghost)
		err = node.LinkBaseWallet(key, 120, conf.ReSync, conf.Tower, conf.Reghost, p)
		if err != nil {
			return err
		}
	}
	// try testnet3
	if conf.Tn3host != "" {
		p := &coinparam.TestNet3Params
		err = node.LinkBaseWallet(
			key, 1210000, conf.ReSync, conf.Tower,
			conf.Tn3host, p)
		if err != nil {
			return err
		}
	}
	// try litecoin regtest
	if conf.Litereghost != "" {
		p := &coinparam.LiteRegNetParams
		err = node.LinkBaseWallet(key, 120, conf.ReSync, conf.Tower, conf.Litereghost, p)
		if err != nil {
			return err
		}
	}

	// try litecoin testnet4
	if conf.Lt4host != "" {
		p := &coinparam.LiteCoinTestNet4Params
		err = node.LinkBaseWallet(
			key, p.StartHeight, conf.ReSync, conf.Tower,
			conf.Lt4host, p)
		if err != nil {
			return err
		}
	}
	// try vertcoin testnet
	if conf.Tvtchost != "" {
		p := &coinparam.VertcoinTestNetParams
		err = node.LinkBaseWallet(
			key, 0, conf.ReSync, conf.Tower,
			conf.Tvtchost, p)
		if err != nil {
			return err
		}
	}
	// try vertcoin mainnet
	if conf.Vtchost != "" {
		p := &coinparam.VertcoinParams
		err = node.LinkBaseWallet(
			key, p.StartHeight, conf.ReSync, conf.Tower,
			conf.Vtchost, p)
		if err != nil {
			return err
		}

	}
	return nil
}

func main() {

	conf := config{
		LitHomeDir: defaultLitHomeDirName,
		ConfigFile: defaultConfigFile,
		Rpcport:    defaultRpcport,
		TrackerURL: defaultTrackerURL,
	}

	// Pre-parse the command line options to see if an alternative config
	// file or the version flag was specified.  Any errors aside from the
	// help message error can be ignored here since they will be caught by
	// the final parse below.
	preconf := conf
	preParser := newConfigParser(&preconf, flags.HelpFlag)
	_, err := preParser.Parse()
	if err != nil { // if there is some sort of error while parsing the CLI arguments
		if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
			fmt.Fprintln(os.Stderr, err)
			log.Fatal(err)
			return
			// return nil, nil, err
		}
	}

	// appName := filepath.Base(os.Args[0])
	// appName = strings.TrimSuffix(appName, filepath.Ext(appName))
	// usageMessage := fmt.Sprintf("Use %s -h to show usage", appName)
	// if preconf.ShowVersion {
	// 	fmt.Println(appName, "version", version())
	// 	os.Exit(0)
	// }

	// Load additional config from file
	var configFileError error
	parser := newConfigParser(&conf, flags.Default) // Single line command to read all the CLI params passed

	// creates a directory in the absolute sense
	_, err = os.Stat(preconf.LitHomeDir)
	if os.IsNotExist(err) {
		os.Mkdir(preconf.LitHomeDir, 0700)
		fmt.Println("Creating a new config file")
		err := createDefaultConfigFile(preconf.LitHomeDir) // Source of error
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error creating a "+
				"default config file: %v\n", err)
		}
	}

	// seems wrong / does nothing?
	//	if err != nil {
	//		fmt.Println("Error while creating a directory")
	//		fmt.Println(err)
	//	}

	if !(preconf.ConfigFile != defaultConfigFile) {
		if _, err := os.Stat(filepath.Join(filepath.Join(preconf.LitHomeDir), "lit.conf")); os.IsNotExist(err) {
			if err != nil {
				fmt.Println(err)
			}
			fmt.Println("Creating a new config file")
			err1 := createDefaultConfigFile(filepath.Join(preconf.LitHomeDir)) // Source of error
			if err1 != nil {
				fmt.Fprintf(os.Stderr, "Error creating a "+
					"default config file: %v\n", err)
			}
		}
		preconf.ConfigFile = filepath.Join(filepath.Join(preconf.LitHomeDir), "lit.conf")
		// lets parse the config file provided, if any
		err := flags.NewIniParser(parser).ParseFile(preconf.ConfigFile)
		if err != nil {
			_, ok := err.(*os.PathError)
			if !ok {
				fmt.Fprintf(os.Stderr, "Error parsing config file: %s\n",
					err.Error())
				log.Fatal(err)
			}
			configFileError = err
		}
	}

	// this seems to do nothing.
	/*
		// Parse command line options again to ensure they take precedence.
		remainingArgs, err := parser.Parse()
		if err != nil {
			if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
				// fmt.Fprintln(os.Stderr, usageMessage)
			}
			log.Fatal(err)
		}
	*/

	if configFileError != nil {
		fmt.Printf("%s\n", configFileError.Error())
	}

	logFilePath := filepath.Join(conf.LitHomeDir, "lit.log")

	// also does nothing
	/*
		if remainingArgs != nil {
			//fmt.Printf("%v", remainingArgs)
		}
	*/

	logfile, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	defer logfile.Close()

	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)

	if conf.Verbose {
		logOutput := io.MultiWriter(os.Stdout, logfile)
		log.SetOutput(logOutput)
	} else {
		log.SetOutput(logfile)
	}

	// Allow node with no linked wallets, for testing.
	// TODO Should update tests and disallow nodes without wallets later.
	//	if conf.Tn3host == "" && conf.Lt4host == "" && conf.Reghost == "" {
	//		log.Fatal("error: no network specified; use -tn3, -reg, -lt4")
	//	}

	// Keys: the litNode, and wallits, all get 32 byte keys.
	// Right now though, they all get the *same* key.  For lit as a single binary
	// now, all using the same key makes sense; could split up later.

	keyFilePath := filepath.Join(conf.LitHomeDir, defaultKeyFileName)

	// read key file (generate if not found)
	key, err := lnutil.ReadKeyFile(keyFilePath)
	if err != nil {
		log.Fatal(err)
	}

	// Setup LN node.  Activate Tower if in hard mode.
	// give node and below file pathof lit home directoy
	node, err := qln.NewLitNode(key, conf.LitHomeDir, conf.TrackerURL)
	if err != nil {
		log.Fatal(err)
	}

	// node is up; link wallets based on args
	err = linkWallets(node, key, &conf)
	if err != nil {
		log.Fatal(err)
	}

	rpcl := new(litrpc.LitRPC)
	rpcl.Node = node
	rpcl.OffButton = make(chan bool, 1)

	go litrpc.RPCListen(rpcl, conf.Rpcport)
	litbamf.BamfListen(conf.Rpcport, conf.LitHomeDir)

	<-rpcl.OffButton
	fmt.Printf("Got stop request\n")
	time.Sleep(time.Second)

	return
	// New directory being created over at PWD
	// conf file being created at /
}

func createDefaultConfigFile(destinationPath string) error {

	// We assume sample config file path is same as binary TODO: change to ~/.lit/config/
	path, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		return err
	}
	sampleConfigPath := filepath.Join(path, defaultConfigFilename)

	// We generate a random user and password
	randomBytes := make([]byte, 20)
	_, err = rand.Read(randomBytes)
	if err != nil {
		return err
	}
	generatedRPCUser := base64.StdEncoding.EncodeToString(randomBytes)

	_, err = rand.Read(randomBytes)
	if err != nil {
		return err
	}
	generatedRPCPass := base64.StdEncoding.EncodeToString(randomBytes)

	src, err := os.Open(sampleConfigPath)
	if err != nil {
		return err
	}
	defer src.Close()

	dest, err := os.OpenFile(filepath.Join(destinationPath, defaultConfigFilename),
		os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer dest.Close()

	// We copy every line from the sample config file to the destination,
	// only replacing the two lines for rpcuser and rpcpass
	reader := bufio.NewReader(src)
	for err != io.EOF {
		var line string
		line, err = reader.ReadString('\n')
		if err != nil && err != io.EOF {
			return err
		}

		if strings.Contains(line, "rpcuser=") {
			line = "rpcuser=" + generatedRPCUser + "\n"
		} else if strings.Contains(line, "rpcpass=") {
			line = "rpcpass=" + generatedRPCPass + "\n"
		}

		if _, err := dest.WriteString(line); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>re-parse args<commit_after>package main

import (
	"bufio"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	flags "github.com/jessevdk/go-flags"
	"github.com/mit-dci/lit/coinparam"
	"github.com/mit-dci/lit/litbamf"
	"github.com/mit-dci/lit/litrpc"
	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/qln"
)

type config struct { // define a struct for usage with go-flags
	Tn3host     string `long:"tn3" description:"Connect to bitcoin testnet3."`
	Bc2host     string `long:"bc2" description:"bc2 full node."`
	Lt4host     string `long:"lt4" description:"Connect to litecoin testnet4."`
	Reghost     string `long:"reg" description:"Connect to bitcoin regtest."`
	Litereghost string `long:"litereg" description:"Connect to litecoin regtest."`
	Tvtchost    string `long:"tvtc" description:"Connect to Vertcoin test node."`
	Vtchost     string `long:"vtc" description:"Connect to Vertcoin."`
	LitHomeDir  string `long:"dir" description:"Specify Home Directory of lit as an absolute path."`
	TrackerURL  string `long:"tracker" description:"LN address tracker URL http|https://host:port"`
	ConfigFile  string

	ReSync  bool `short:"r" long:"reSync" description:"Resync from the given tip."`
	Tower   bool `long:"tower" description:"Watchtower: Run a watching node"`
	Hard    bool `short:"t" long:"hard" description:"Flag to set networks."`
	Verbose bool `short:"v" long:"verbose" description:"Set verbosity to true."`

	Rpcport uint16 `short:"p" long:"rpcport" description:"Set RPC port to connect to"`

	Params *coinparam.Params
}

var (
	defaultLitHomeDirName = os.Getenv("HOME") + "/.lit"
	defaultTrackerURL     = "http://ni.media.mit.edu:46580"
	defaultKeyFileName    = "privkey.hex"
	defaultConfigFilename = "lit.conf"
	defaultHomeDir        = os.Getenv("HOME")
	defaultConfigFile     = filepath.Join(os.Getenv("HOME"), "/.lit/lit.conf")
	defaultRpcport        = uint16(8001)
)

func fileExists(name string) bool {
	if _, err := os.Stat(name); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

// newConfigParser returns a new command line flags parser.
func newConfigParser(conf *config, options flags.Options) *flags.Parser {
	parser := flags.NewParser(conf, options)
	return parser
}
func linkWallets(node *qln.LitNode, key *[32]byte, conf *config) error {
	// for now, wallets are linked to the litnode on startup, and
	// can't appear / disappear while it's running.  Later
	// could support dynamically adding / removing wallets

	// order matters; the first registered wallet becomes the default

	var err error
	// try regtest
	if conf.Reghost != "" {
		p := &coinparam.RegressionNetParams
		fmt.Printf("reg: %s\n", conf.Reghost)
		err = node.LinkBaseWallet(key, 120, conf.ReSync, conf.Tower, conf.Reghost, p)
		if err != nil {
			return err
		}
	}
	// try testnet3
	if conf.Tn3host != "" {
		p := &coinparam.TestNet3Params
		err = node.LinkBaseWallet(
			key, 1210000, conf.ReSync, conf.Tower,
			conf.Tn3host, p)
		if err != nil {
			return err
		}
	}
	// try litecoin regtest
	if conf.Litereghost != "" {
		p := &coinparam.LiteRegNetParams
		err = node.LinkBaseWallet(key, 120, conf.ReSync, conf.Tower, conf.Litereghost, p)
		if err != nil {
			return err
		}
	}

	// try litecoin testnet4
	if conf.Lt4host != "" {
		p := &coinparam.LiteCoinTestNet4Params
		err = node.LinkBaseWallet(
			key, p.StartHeight, conf.ReSync, conf.Tower,
			conf.Lt4host, p)
		if err != nil {
			return err
		}
	}
	// try vertcoin testnet
	if conf.Tvtchost != "" {
		p := &coinparam.VertcoinTestNetParams
		err = node.LinkBaseWallet(
			key, 0, conf.ReSync, conf.Tower,
			conf.Tvtchost, p)
		if err != nil {
			return err
		}
	}
	// try vertcoin mainnet
	if conf.Vtchost != "" {
		p := &coinparam.VertcoinParams
		err = node.LinkBaseWallet(
			key, p.StartHeight, conf.ReSync, conf.Tower,
			conf.Vtchost, p)
		if err != nil {
			return err
		}

	}
	return nil
}

func main() {

	conf := config{
		LitHomeDir: defaultLitHomeDirName,
		ConfigFile: defaultConfigFile,
		Rpcport:    defaultRpcport,
		TrackerURL: defaultTrackerURL,
	}

	// Pre-parse the command line options to see if an alternative config
	// file or the version flag was specified.  Any errors aside from the
	// help message error can be ignored here since they will be caught by
	// the final parse below.
	preconf := conf
	preParser := newConfigParser(&preconf, flags.HelpFlag)
	_, err := preParser.Parse()
	if err != nil { // if there is some sort of error while parsing the CLI arguments
		if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
			fmt.Fprintln(os.Stderr, err)
			log.Fatal(err)
			return
			// return nil, nil, err
		}
	}

	// appName := filepath.Base(os.Args[0])
	// appName = strings.TrimSuffix(appName, filepath.Ext(appName))
	// usageMessage := fmt.Sprintf("Use %s -h to show usage", appName)
	// if preconf.ShowVersion {
	// 	fmt.Println(appName, "version", version())
	// 	os.Exit(0)
	// }

	// Load additional config from file
	var configFileError error
	parser := newConfigParser(&conf, flags.Default) // Single line command to read all the CLI params passed

	// creates a directory in the absolute sense
	_, err = os.Stat(preconf.LitHomeDir)
	if os.IsNotExist(err) {
		os.Mkdir(preconf.LitHomeDir, 0700)
		fmt.Println("Creating a new config file")
		err := createDefaultConfigFile(preconf.LitHomeDir) // Source of error
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error creating a "+
				"default config file: %v\n", err)
		}
	}

	// seems wrong / does nothing?
	//	if err != nil {
	//		fmt.Println("Error while creating a directory")
	//		fmt.Println(err)
	//	}

	if !(preconf.ConfigFile != defaultConfigFile) {
		if _, err := os.Stat(filepath.Join(filepath.Join(preconf.LitHomeDir), "lit.conf")); os.IsNotExist(err) {
			if err != nil {
				fmt.Println(err)
			}
			fmt.Println("Creating a new config file")
			err1 := createDefaultConfigFile(filepath.Join(preconf.LitHomeDir)) // Source of error
			if err1 != nil {
				fmt.Fprintf(os.Stderr, "Error creating a "+
					"default config file: %v\n", err)
			}
		}
		preconf.ConfigFile = filepath.Join(filepath.Join(preconf.LitHomeDir), "lit.conf")
		// lets parse the config file provided, if any
		err := flags.NewIniParser(parser).ParseFile(preconf.ConfigFile)
		if err != nil {
			_, ok := err.(*os.PathError)
			if !ok {
				fmt.Fprintf(os.Stderr, "Error parsing config file: %s\n",
					err.Error())
				log.Fatal(err)
			}
			configFileError = err
		}
	}

	// Parse command line options again to ensure they take precedence.
	_, err = parser.Parse()
	if err != nil {
		// huh?
		//		if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
		//		}
		log.Fatal(err)
	}

	if configFileError != nil {
		fmt.Printf("%s\n", configFileError.Error())
	}

	logFilePath := filepath.Join(conf.LitHomeDir, "lit.log")

	// also does nothing
	/*
		if remainingArgs != nil {
			//fmt.Printf("%v", remainingArgs)
		}
	*/

	logfile, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	defer logfile.Close()

	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)

	if conf.Verbose {
		logOutput := io.MultiWriter(os.Stdout, logfile)
		log.SetOutput(logOutput)
	} else {
		log.SetOutput(logfile)
	}

	// Allow node with no linked wallets, for testing.
	// TODO Should update tests and disallow nodes without wallets later.
	//	if conf.Tn3host == "" && conf.Lt4host == "" && conf.Reghost == "" {
	//		log.Fatal("error: no network specified; use -tn3, -reg, -lt4")
	//	}

	// Keys: the litNode, and wallits, all get 32 byte keys.
	// Right now though, they all get the *same* key.  For lit as a single binary
	// now, all using the same key makes sense; could split up later.

	keyFilePath := filepath.Join(conf.LitHomeDir, defaultKeyFileName)

	// read key file (generate if not found)
	key, err := lnutil.ReadKeyFile(keyFilePath)
	if err != nil {
		log.Fatal(err)
	}

	// Setup LN node.  Activate Tower if in hard mode.
	// give node and below file pathof lit home directoy
	node, err := qln.NewLitNode(key, conf.LitHomeDir, conf.TrackerURL)
	if err != nil {
		log.Fatal(err)
	}

	// node is up; link wallets based on args
	err = linkWallets(node, key, &conf)
	if err != nil {
		log.Fatal(err)
	}

	rpcl := new(litrpc.LitRPC)
	rpcl.Node = node
	rpcl.OffButton = make(chan bool, 1)

	go litrpc.RPCListen(rpcl, conf.Rpcport)
	litbamf.BamfListen(conf.Rpcport, conf.LitHomeDir)

	<-rpcl.OffButton
	fmt.Printf("Got stop request\n")
	time.Sleep(time.Second)

	return
	// New directory being created over at PWD
	// conf file being created at /
}

func createDefaultConfigFile(destinationPath string) error {

	// We assume sample config file path is same as binary TODO: change to ~/.lit/config/
	path, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		return err
	}
	sampleConfigPath := filepath.Join(path, defaultConfigFilename)

	// We generate a random user and password
	randomBytes := make([]byte, 20)
	_, err = rand.Read(randomBytes)
	if err != nil {
		return err
	}
	generatedRPCUser := base64.StdEncoding.EncodeToString(randomBytes)

	_, err = rand.Read(randomBytes)
	if err != nil {
		return err
	}
	generatedRPCPass := base64.StdEncoding.EncodeToString(randomBytes)

	src, err := os.Open(sampleConfigPath)
	if err != nil {
		return err
	}
	defer src.Close()

	dest, err := os.OpenFile(filepath.Join(destinationPath, defaultConfigFilename),
		os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer dest.Close()

	// We copy every line from the sample config file to the destination,
	// only replacing the two lines for rpcuser and rpcpass
	reader := bufio.NewReader(src)
	for err != io.EOF {
		var line string
		line, err = reader.ReadString('\n')
		if err != nil && err != io.EOF {
			return err
		}

		if strings.Contains(line, "rpcuser=") {
			line = "rpcuser=" + generatedRPCUser + "\n"
		} else if strings.Contains(line, "rpcpass=") {
			line = "rpcpass=" + generatedRPCPass + "\n"
		}

		if _, err := dest.WriteString(line); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>