<commit_before>package db

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/boltdb/bolt"
	"github.com/subutai-io/base/agent/log"

	"github.com/subutai-io/gorjun/config"
)

var (
	bucket = []byte("MyBucket")
	search = []byte("SearchIndex")
	users  = []byte("Users")
	tokens = []byte("Tokens")
	authid = []byte("AuthID")
	db     = initdb()
)

func initdb() *bolt.DB {
	db, err := bolt.Open(config.Path+"my.db", 0600, nil)
	log.Check(log.FatalLevel, "Openning DB: my.db", err)

	err = db.Update(func(tx *bolt.Tx) error {
		for _, b := range [][]byte{bucket, search, users, tokens, authid} {
			_, err := tx.CreateBucketIfNotExists(b)
			log.Check(log.FatalLevel, "Creating bucket: "+string(b), err)
		}
		return nil
	})
	log.Check(log.FatalLevel, "Finishing update transaction", err)

	return db
}

func Write(owner, key, value string, options ...map[string]string) {
	if len(owner) == 0 {
		owner = "public"
	}
	err := db.Update(func(tx *bolt.Tx) error {
		now, _ := time.Now().MarshalText()

		// Associating files with user
		b, _ := tx.Bucket(users).CreateBucketIfNotExists([]byte(owner))
		if b, err := b.CreateBucketIfNotExists([]byte("files")); err == nil {
			b.Put([]byte(key), []byte(value))
		}

		// Creating new record about file
		if b, err := tx.Bucket(bucket).CreateBucket([]byte(key)); err == nil {
			b.Put([]byte("date"), now)
			b.Put([]byte("name"), []byte(value))

			// Getting file size
			if f, err := os.Open(config.Filepath + key); err == nil {
				fi, _ := f.Stat()
				f.Close()
				b.Put([]byte("size"), []byte(fmt.Sprint(fi.Size())))
			}

			// Writing optional parameters for file
			for i, _ := range options {
				for k, v := range options[i] {
					b.Put([]byte(k), []byte(v))
				}
			}

			// Adding search index for files
			b, _ = tx.Bucket(search).CreateBucketIfNotExists([]byte(value))
			b.Put(now, []byte(key))

		}

		// Adding owners and shares to files
		if b := tx.Bucket(bucket).Bucket([]byte(key)); b != nil {
			if c, _ := b.CreateBucketIfNotExists([]byte("owner")); c != nil {
				//If value is not empty, we are assuming that it is a signature (or any other personal info)
				//Otherwise we are just adding new owner
				if len(value) != 0 && len(options) == 0 {
					c.Put([]byte(owner), []byte(value))
				} else {
					c.Put([]byte(owner), []byte("w"))
				}
			}
			if b, _ = b.CreateBucketIfNotExists([]byte("scope")); b != nil {
				if b, _ = b.CreateBucketIfNotExists([]byte(owner)); b != nil {
				}
			}
		}
		return nil
	})
	log.Check(log.WarnLevel, "Writing data to db", err)
}

func Delete(owner, key string) (remains int) {
	db.Update(func(tx *bolt.Tx) error {
		var filename []byte

		// Deleting file association with user
		if b := tx.Bucket(users).Bucket([]byte(owner)); b != nil {
			if b := b.Bucket([]byte("files")); b != nil {
				filename = b.Get([]byte(key))
				b.Delete([]byte(key))
			}
		}

		// Deleting user association with file
		if b := tx.Bucket(bucket).Bucket([]byte(key)); b != nil {
			if c := b.Bucket([]byte("scope")); c != nil {
				c.Delete([]byte(owner))
			}
			if b := b.Bucket([]byte("owner")); b != nil {
				b.Delete([]byte(owner))
				remains = b.Stats().KeyN - 1
			}
		}

		// Removing indexes and file only if no file owners left
		if remains <= 0 {
			// Deleting search index
			if b := tx.Bucket(search).Bucket([]byte(filename)); b != nil {
				b.ForEach(func(k, v []byte) error {
					if string(v) == key {
						b.Delete(k)
					}
					return nil
				})
			}

			// Removing file from DB
			tx.Bucket(bucket).DeleteBucket([]byte(key))
		}
		return nil
	})

	return
}

func Read(key string) (val string) {
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(key)); b != nil {
			if value := b.Get([]byte("name")); value != nil {
				val = string(value)
			}
		}
		return nil
	})
	return val
}

func List() map[string]string {
	list := make(map[string]string)
	db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(bucket)
		b.ForEach(func(k, v []byte) error {
			if value := b.Bucket(k).Get([]byte("name")); value != nil {
				list[string(k)] = string(value)
			}
			return nil
		})
		return nil
	})
	return list
}

func Info(hash string) map[string]string {
	list := make(map[string]string)
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			b.ForEach(func(k, v []byte) error {
				list[string(k)] = string(v)
				return nil
			})
		}
		return nil
	})
	list["owner"] = "public"
	return list
}

func Close() {
	db.Close()
}

func Search(query string) map[string]string {
	list := make(map[string]string)
	db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(search)
		c := b.Cursor()
		for k, _ := c.Seek([]byte(query)); len(k) > 0 && bytes.HasPrefix(k, []byte(query)); k, _ = c.Next() {
			b.Bucket(k).ForEach(func(kk, vv []byte) error {
				list[string(vv)] = string(k)
				return nil
			})
		}
		return nil
	})
	return list
}

func LastHash(name, t string) (hash string) {
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(search).Bucket([]byte(name)); b != nil {
			c := b.Cursor()
			for k, v := c.Last(); k != nil; k, v = c.Prev() {
				if t == "" || t == Info(string(v))["type"] {
					hash = string(v)
					break
				}
			}
		}
		return nil
	})
	return hash
}

func RegisterUser(name, key []byte) {
	db.Update(func(tx *bolt.Tx) error {
		b, err := tx.Bucket(users).CreateBucket([]byte(name))
		if !log.Check(log.WarnLevel, "Registering user "+string(name), err) {
			b.Put([]byte("key"), key)
		}
		return err
	})
}

func UserKey(name string) (key string) {
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(users).Bucket([]byte(name)); b != nil {
			if value := b.Get([]byte("key")); value != nil {
				key = string(value)
			}
		}
		return nil
	})
	return key
}

func SaveToken(name, token string) {
	db.Update(func(tx *bolt.Tx) error {
		if b, _ := tx.Bucket(tokens).CreateBucketIfNotExists([]byte(token)); b != nil {
			b.Put([]byte("name"), []byte(name))
			now, _ := time.Now().MarshalText()
			b.Put([]byte("date"), now)
		}
		return nil
	})
}

func CheckToken(token string) (name string) {
	token = fmt.Sprintf("%x", sha256.Sum256([]byte(token)))

	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(tokens).Bucket([]byte(token)); b != nil {
			date := new(time.Time)
			date.UnmarshalText(b.Get([]byte("date")))
			if date.Add(time.Minute * 60).Before(time.Now()) {
				return nil
			}
			if value := b.Get([]byte("name")); value != nil {
				name = string(value)
			}
		}
		return nil
	})
	return name
}

func SaveAuthID(name, token string) {
	db.Update(func(tx *bolt.Tx) error {
		tx.Bucket(authid).Put([]byte(token), []byte(name))
		return nil
	})
}

func CheckAuthID(token string) (name string) {
	db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(authid)
		if value := b.Get([]byte(token)); value != nil {
			name = string(value)
			b.Delete([]byte(token))
		}
		return nil
	})
	return name
}

// FileOwner provides list of file owners
func FileOwner(hash string) (list []string) {
	list = []string{}
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("owner")); b != nil {
				b.ForEach(func(k, v []byte) error {
					list = append(list, string(k))
					return nil
				})
			}
		}
		return nil
	})
	return list
}

// CheckOwner checks if user owns particular file
func CheckOwner(owner, hash string) (res bool) {
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("owner")); b != nil && b.Get([]byte(owner)) != nil {
				res = true
			}
		}
		return nil
	})
	return res
}

func FileSignatures(hash string) (list map[string]string) {
	list = map[string]string{}
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("owner")); b != nil {
				b.ForEach(func(k, v []byte) error {
					if string(v) != "w" {
						list[string(k)] = string(v)
					}
					return nil
				})
			}
		}
		return nil
	})
	return list
}

// UserFile searching file at particular user. It returns list of hashes of files with required name.
func UserFile(owner, file string) (list []string) {
	if len(owner) == 0 {
		owner = "public"
	}
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(users).Bucket([]byte(owner)); b != nil {
			if files := b.Bucket([]byte("files")); files != nil {
				files.ForEach(func(k, v []byte) error {
					if Read(string(k)) == file {
						list = append(list, string(k))
					}
					return nil
				})
			}
		}
		return nil
	})
	return list
}

func GetScope(hash, owner string) (scope []string) {
	scope = []string{}
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("scope")); b != nil {
				if b := b.Bucket([]byte(owner)); b != nil {
					b.ForEach(func(k, v []byte) error {
						scope = append(scope, string(k))
						return nil
					})
				}
			}
		}
		return nil
	})
	return scope
}

func ShareWith(hash, owner, user string) {
	db.Update(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("scope")); b != nil {
				if b := b.Bucket([]byte(owner)); b != nil {
					b.Put([]byte(user), []byte("w"))
				}
			}
		}
		return nil
	})
}

func UnshareWith(hash, owner, user string) {
	db.Update(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("scope")); b != nil {
				if b := b.Bucket([]byte(owner)); b != nil {
					b.Delete([]byte(user))
				}
			}
		}
		return nil
	})
}

func CheckShare(hash, user string) (shared bool) {
	// log.Warn("hash: " + hash + ", user: " + user)
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("scope")); b != nil {
				b.ForEach(func(k, v []byte) error {
					// log.Warn("Owner: " + string(k))
					if strings.EqualFold(string(k), user) {
						shared = true
					} else if b := b.Bucket(k); b != nil {
						b.ForEach(func(k1, v1 []byte) error {
							// log.Warn("+++" + string(k1))
							if strings.EqualFold(string(k1), user) {
								shared = true
							}
							return nil
						})
					}
					return nil
				})
			}
		}
		return nil
	})
	return
}

func Public(hash string) (public bool) {
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("scope")); b != nil {
				b.ForEach(func(k, v []byte) error {
					if b := b.Bucket([]byte(k)); b != nil {
						k, _ := b.Cursor().First()
						if k == nil {
							public = true
						}
					}
					return nil
				})
			} else {
				public = true
			}
		}
		return nil
	})
	return
}
<commit_msg>Remove signatures from search index<commit_after>package db

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/boltdb/bolt"
	"github.com/subutai-io/base/agent/log"

	"github.com/subutai-io/gorjun/config"
)

var (
	bucket = []byte("MyBucket")
	search = []byte("SearchIndex")
	users  = []byte("Users")
	tokens = []byte("Tokens")
	authid = []byte("AuthID")
	db     = initdb()
)

func initdb() *bolt.DB {
	db, err := bolt.Open(config.Path+"my.db", 0600, nil)
	log.Check(log.FatalLevel, "Openning DB: my.db", err)

	err = db.Update(func(tx *bolt.Tx) error {
		for _, b := range [][]byte{bucket, search, users, tokens, authid} {
			_, err := tx.CreateBucketIfNotExists(b)
			log.Check(log.FatalLevel, "Creating bucket: "+string(b), err)
		}
		return nil
	})
	log.Check(log.FatalLevel, "Finishing update transaction", err)

	return db
}

func Write(owner, key, value string, options ...map[string]string) {
	if len(owner) == 0 {
		owner = "public"
	}
	err := db.Update(func(tx *bolt.Tx) error {
		now, _ := time.Now().MarshalText()

		// Associating files with user
		b, _ := tx.Bucket(users).CreateBucketIfNotExists([]byte(owner))
		if b, err := b.CreateBucketIfNotExists([]byte("files")); err == nil {
			if k, _ := b.Cursor().Seek([]byte(key)); k == nil {
				b.Put([]byte(key), []byte(value))
			}
		}

		// Creating new record about file
		if b, err := tx.Bucket(bucket).CreateBucket([]byte(key)); err == nil {
			b.Put([]byte("date"), now)
			b.Put([]byte("name"), []byte(value))

			// Getting file size
			if f, err := os.Open(config.Filepath + key); err == nil {
				fi, _ := f.Stat()
				f.Close()
				b.Put([]byte("size"), []byte(fmt.Sprint(fi.Size())))
			}

			// Writing optional parameters for file
			for i, _ := range options {
				for k, v := range options[i] {
					b.Put([]byte(k), []byte(v))
				}
			}

			// Adding search index for files
			b, _ = tx.Bucket(search).CreateBucketIfNotExists([]byte(value))
			b.Put(now, []byte(key))

		}

		// Adding owners and shares to files
		if b := tx.Bucket(bucket).Bucket([]byte(key)); b != nil {
			if c, _ := b.CreateBucketIfNotExists([]byte("owner")); c != nil {
				//If value is not empty, we are assuming that it is a signature (or any other personal info)
				//Otherwise we are just adding new owner
				if len(value) != 0 && len(options) == 0 {
					c.Put([]byte(owner), []byte(value))
				} else {
					c.Put([]byte(owner), []byte("w"))
				}
			}
			if b, _ = b.CreateBucketIfNotExists([]byte("scope")); b != nil {
				if b, _ = b.CreateBucketIfNotExists([]byte(owner)); b != nil {
				}
			}
		}
		return nil
	})
	log.Check(log.WarnLevel, "Writing data to db", err)
}

func Delete(owner, key string) (remains int) {
	db.Update(func(tx *bolt.Tx) error {
		var filename []byte

		// Deleting file association with user
		if b := tx.Bucket(users).Bucket([]byte(owner)); b != nil {
			if b := b.Bucket([]byte("files")); b != nil {
				filename = b.Get([]byte(key))
				b.Delete([]byte(key))
			}
		}

		// Deleting user association with file
		if b := tx.Bucket(bucket).Bucket([]byte(key)); b != nil {
			if c := b.Bucket([]byte("scope")); c != nil {
				c.Delete([]byte(owner))
			}
			if b := b.Bucket([]byte("owner")); b != nil {
				b.Delete([]byte(owner))
				remains = b.Stats().KeyN - 1
			}
		}

		// Removing indexes and file only if no file owners left
		if remains <= 0 {
			// Deleting search index
			if b := tx.Bucket(search).Bucket([]byte(filename)); b != nil {
				b.ForEach(func(k, v []byte) error {
					if string(v) == key {
						b.Delete(k)
					}
					return nil
				})
			}

			// Removing file from DB
			tx.Bucket(bucket).DeleteBucket([]byte(key))
		}
		return nil
	})

	return
}

func Read(key string) (val string) {
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(key)); b != nil {
			if value := b.Get([]byte("name")); value != nil {
				val = string(value)
			}
		}
		return nil
	})
	return val
}

func List() map[string]string {
	list := make(map[string]string)
	db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(bucket)
		b.ForEach(func(k, v []byte) error {
			if value := b.Bucket(k).Get([]byte("name")); value != nil {
				list[string(k)] = string(value)
			}
			return nil
		})
		return nil
	})
	return list
}

func Info(hash string) map[string]string {
	list := make(map[string]string)
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			b.ForEach(func(k, v []byte) error {
				list[string(k)] = string(v)
				return nil
			})
		}
		return nil
	})
	list["owner"] = "public"
	return list
}

func Close() {
	db.Close()
}

func Search(query string) map[string]string {
	list := make(map[string]string)
	db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(search)
		c := b.Cursor()
		for k, _ := c.Seek([]byte(query)); len(k) > 0 && bytes.HasPrefix(k, []byte(query)); k, _ = c.Next() {
			b.Bucket(k).ForEach(func(kk, vv []byte) error {
				list[string(vv)] = string(k)
				return nil
			})
		}
		return nil
	})
	return list
}

func LastHash(name, t string) (hash string) {
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(search).Bucket([]byte(name)); b != nil {
			c := b.Cursor()
			for k, v := c.Last(); k != nil; k, v = c.Prev() {
				if t == "" || t == Info(string(v))["type"] {
					hash = string(v)
					break
				}
			}
		}
		return nil
	})
	return hash
}

func RegisterUser(name, key []byte) {
	db.Update(func(tx *bolt.Tx) error {
		b, err := tx.Bucket(users).CreateBucket([]byte(name))
		if !log.Check(log.WarnLevel, "Registering user "+string(name), err) {
			b.Put([]byte("key"), key)
		}
		return err
	})
}

func UserKey(name string) (key string) {
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(users).Bucket([]byte(name)); b != nil {
			if value := b.Get([]byte("key")); value != nil {
				key = string(value)
			}
		}
		return nil
	})
	return key
}

func SaveToken(name, token string) {
	db.Update(func(tx *bolt.Tx) error {
		if b, _ := tx.Bucket(tokens).CreateBucketIfNotExists([]byte(token)); b != nil {
			b.Put([]byte("name"), []byte(name))
			now, _ := time.Now().MarshalText()
			b.Put([]byte("date"), now)
		}
		return nil
	})
}

func CheckToken(token string) (name string) {
	token = fmt.Sprintf("%x", sha256.Sum256([]byte(token)))

	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(tokens).Bucket([]byte(token)); b != nil {
			date := new(time.Time)
			date.UnmarshalText(b.Get([]byte("date")))
			if date.Add(time.Minute * 60).Before(time.Now()) {
				return nil
			}
			if value := b.Get([]byte("name")); value != nil {
				name = string(value)
			}
		}
		return nil
	})
	return name
}

func SaveAuthID(name, token string) {
	db.Update(func(tx *bolt.Tx) error {
		tx.Bucket(authid).Put([]byte(token), []byte(name))
		return nil
	})
}

func CheckAuthID(token string) (name string) {
	db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(authid)
		if value := b.Get([]byte(token)); value != nil {
			name = string(value)
			b.Delete([]byte(token))
		}
		return nil
	})
	return name
}

// FileOwner provides list of file owners
func FileOwner(hash string) (list []string) {
	list = []string{}
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("owner")); b != nil {
				b.ForEach(func(k, v []byte) error {
					list = append(list, string(k))
					return nil
				})
			}
		}
		return nil
	})
	return list
}

// CheckOwner checks if user owns particular file
func CheckOwner(owner, hash string) (res bool) {
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("owner")); b != nil && b.Get([]byte(owner)) != nil {
				res = true
			}
		}
		return nil
	})
	return res
}

func FileSignatures(hash string) (list map[string]string) {
	list = map[string]string{}
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("owner")); b != nil {
				b.ForEach(func(k, v []byte) error {
					if string(v) != "w" {
						list[string(k)] = string(v)
					}
					return nil
				})
			}
		}
		return nil
	})
	return list
}

// UserFile searching file at particular user. It returns list of hashes of files with required name.
func UserFile(owner, file string) (list []string) {
	if len(owner) == 0 {
		owner = "public"
	}
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(users).Bucket([]byte(owner)); b != nil {
			if files := b.Bucket([]byte("files")); files != nil {
				files.ForEach(func(k, v []byte) error {
					if Read(string(k)) == file {
						list = append(list, string(k))
					}
					return nil
				})
			}
		}
		return nil
	})
	return list
}

func GetScope(hash, owner string) (scope []string) {
	scope = []string{}
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("scope")); b != nil {
				if b := b.Bucket([]byte(owner)); b != nil {
					b.ForEach(func(k, v []byte) error {
						scope = append(scope, string(k))
						return nil
					})
				}
			}
		}
		return nil
	})
	return scope
}

func ShareWith(hash, owner, user string) {
	db.Update(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("scope")); b != nil {
				if b := b.Bucket([]byte(owner)); b != nil {
					b.Put([]byte(user), []byte("w"))
				}
			}
		}
		return nil
	})
}

func UnshareWith(hash, owner, user string) {
	db.Update(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("scope")); b != nil {
				if b := b.Bucket([]byte(owner)); b != nil {
					b.Delete([]byte(user))
				}
			}
		}
		return nil
	})
}

func CheckShare(hash, user string) (shared bool) {
	// log.Warn("hash: " + hash + ", user: " + user)
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("scope")); b != nil {
				b.ForEach(func(k, v []byte) error {
					// log.Warn("Owner: " + string(k))
					if strings.EqualFold(string(k), user) {
						shared = true
					} else if b := b.Bucket(k); b != nil {
						b.ForEach(func(k1, v1 []byte) error {
							// log.Warn("+++" + string(k1))
							if strings.EqualFold(string(k1), user) {
								shared = true
							}
							return nil
						})
					}
					return nil
				})
			}
		}
		return nil
	})
	return
}

func Public(hash string) (public bool) {
	db.View(func(tx *bolt.Tx) error {
		if b := tx.Bucket(bucket).Bucket([]byte(hash)); b != nil {
			if b := b.Bucket([]byte("scope")); b != nil {
				b.ForEach(func(k, v []byte) error {
					if b := b.Bucket([]byte(k)); b != nil {
						k, _ := b.Cursor().First()
						if k == nil {
							public = true
						}
					}
					return nil
				})
			} else {
				public = true
			}
		}
		return nil
	})
	return
}
<|endoftext|>


<commit_before>package db

import (
	"database/sql"

	_ "github.com/mattn/go-sqlite3" // required blank import
)

// DB is the SQL database.
type DB struct {
	conn *sql.DB
}

type Result sql.Result
type Row sql.Row
type Rows sql.Rows

// Open an existing database, creating it if it does not exist.
func Open(dbPath string) (*DB, error) {
	dbc, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		return nil, err
	}
	return &DB{
		conn: dbc,
	}, nil
}

// Close closes the underlying database connection.
func (db *DB) Close() error {
	return db.conn.Close()
}

func (db *DB) Execute(queries []string, tx bool) ([]sql.Result, error) {
	type Execer interface {
		Exec(query string, args ...interface{}) (sql.Result, error)
	}

	err := func() (err error) {
		var execer Execer
		defer func() {
			if t, ok := execer.(*sql.Tx); ok {
				if err != nil {
					t.Rollback()
					return
				}
				t.Commit()
			}
		}()

		if tx {
			execer, _ = db.conn.Begin()
		} else {
			execer = db.conn
		}

		for _, q := range queries {
			_, err = execer.Exec(q)
			if err != nil {
				return err
			}
		}
		return nil
	}()

	return nil, err
}

func (db *DB) Query(queries []string, tx bool) ([]*sql.Rows, error) {
	type Queryer interface {
		Query(query string, args ...interface{}) (*sql.Rows, error)
	}

	var allRows []*sql.Rows
	err := func() (err error) {
		var queryer Queryer
		defer func() {
			if t, ok := queryer.(*sql.Tx); ok {
				if err != nil {
					t.Rollback()
					return
				}
				t.Commit()
			}
		}()

		if tx {
			queryer, _ = db.conn.Begin()
		} else {
			queryer = db.conn
		}

		for _, q := range queries {
			rows, err := queryer.Query(q)
			if err != nil {
				return err
			}
			allRows = append(allRows, rows)
		}
		return nil
	}()

	return allRows, err
}
<commit_msg>Query in db package almost there<commit_after>package db

import (
	"database/sql"

	_ "github.com/mattn/go-sqlite3" // required blank import
)

// DB is the SQL database.
type DB struct {
	conn *sql.DB
}

type Result sql.Result
type Rows struct {
	Columns []string
	Values  [][]interface{}
}

// Open an existing database, creating it if it does not exist.
func Open(dbPath string) (*DB, error) {
	dbc, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		return nil, err
	}
	return &DB{
		conn: dbc,
	}, nil
}

// Close closes the underlying database connection.
func (db *DB) Close() error {
	return db.conn.Close()
}

func (db *DB) Execute(queries []string, tx bool) ([]sql.Result, error) {
	type Execer interface {
		Exec(query string, args ...interface{}) (sql.Result, error)
	}

	err := func() (err error) {
		var execer Execer
		defer func() {
			if t, ok := execer.(*sql.Tx); ok {
				if err != nil {
					t.Rollback()
					return
				}
				t.Commit()
			}
		}()

		if tx {
			execer, _ = db.conn.Begin()
		} else {
			execer = db.conn
		}

		for _, q := range queries {
			_, err = execer.Exec(q)
			if err != nil {
				return err
			}
		}
		return nil
	}()

	return nil, err
}

func (db *DB) Query(queries []string, tx bool) ([]Rows, error) {
	type Queryer interface {
		Query(query string, args ...interface{}) (*sql.Rows, error)
	}

	var allRows []Rows
	err := func() (err error) {
		var queryer Queryer
		defer func() {
			if t, ok := queryer.(*sql.Tx); ok {
				if err != nil {
					t.Rollback()
					return
				}
				t.Commit()
			}
		}()

		if tx {
			queryer, _ = db.conn.Begin()
		} else {
			queryer = db.conn
		}

		for _, q := range queries {
			rs, err := queryer.Query(q)
			if err != nil {
				return err
			}
			defer rs.Close() // This adds to all defers, right? Nothing leaks? XXX Could consume memory. Perhaps anon would be best.
			columns, err := rs.Columns()
			if err != nil {
				return err
			}

			var rows Rows
			rows.Columns = columns
			for rs.Next() {
				values := make([]interface{}, len(rows.Columns))
				rawResult := make([]interface{}, len(columns))
				for i := range rawResult {
					values[i] = &rawResult[i]
				}

				err = rs.Scan(values...)
				if err != nil {
					return err
				}
				rows.Values = append(rows.Values, values)

				// I think there is way to fix all this. The Values are *interface{}, but I want interface{} to go up,
				// with the right types inside. http://stackoverflow.com/questions/23507531/is-golangs-sql-package-incapable-of-ad-hoc-exploratory-queries
			}

			allRows = append(allRows, rows)
		}

		return nil
	}()

	return allRows, err
}
<|endoftext|>


<commit_before>package progressui

import (
	"container/ring"
	"context"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
	"time"

	digest "github.com/opencontainers/go-digest"
	"github.com/tonistiigi/units"
)

const antiFlicker = 5 * time.Second
const maxDelay = 10 * time.Second
const minTimeDelta = 5 * time.Second
const minProgressDelta = 0.05 // %

const logsBufferSize = 10

type lastStatus struct {
	Current   int64
	Timestamp time.Time
}

type textMux struct {
	w         io.Writer
	current   digest.Digest
	last      map[string]lastStatus
	notFirst  bool
	nextIndex int
}

func (p *textMux) printVtx(t *trace, dgst digest.Digest) {
	if p.last == nil {
		p.last = make(map[string]lastStatus)
	}

	v, ok := t.byDigest[dgst]
	if !ok {
		return
	}

	if v.index == 0 {
		p.nextIndex++
		v.index = p.nextIndex
	}

	if dgst != p.current {
		if p.current != "" {
			old := t.byDigest[p.current]
			if old.logsPartial {
				fmt.Fprintln(p.w, "")
			}
			old.logsOffset = 0
			old.count = 0
			fmt.Fprintf(p.w, "#%d ...\n", old.index)
		}

		if p.notFirst {
			fmt.Fprintln(p.w, "")
		} else {
			p.notFirst = true
		}

		if os.Getenv("PROGRESS_NO_TRUNC") == "0" {
			fmt.Fprintf(p.w, "#%d %s\n", v.index, limitString(v.Name, 72))
		} else {
			fmt.Fprintf(p.w, "#%d %s\n", v.index, v.Name)
		}
	}

	if len(v.events) != 0 {
		v.logsOffset = 0
	}
	for _, ev := range v.events {
		fmt.Fprintf(p.w, "#%d %s\n", v.index, ev)
	}
	v.events = v.events[:0]

	isOpenStatus := false // remote cache loading can currently produce status updates without active vertex
	for _, s := range v.statuses {
		if _, ok := v.statusUpdates[s.ID]; ok {
			doPrint := true

			if last, ok := p.last[s.ID]; ok && s.Completed == nil {
				var progressDelta float64
				if s.Total > 0 {
					progressDelta = float64(s.Current-last.Current) / float64(s.Total)
				}
				timeDelta := s.Timestamp.Sub(last.Timestamp)
				if progressDelta < minProgressDelta && timeDelta < minTimeDelta {
					doPrint = false
				}
			}

			if !doPrint {
				continue
			}

			p.last[s.ID] = lastStatus{
				Timestamp: s.Timestamp,
				Current:   s.Current,
			}

			var bytes string
			if s.Total != 0 {
				bytes = fmt.Sprintf(" %.2f / %.2f", units.Bytes(s.Current), units.Bytes(s.Total))
			} else if s.Current != 0 {
				bytes = fmt.Sprintf(" %.2f", units.Bytes(s.Current))
			}
			var tm string
			endTime := s.Timestamp
			if s.Completed != nil {
				endTime = *s.Completed
			}
			if s.Started != nil {
				diff := endTime.Sub(*s.Started).Seconds()
				if diff > 0.01 {
					tm = fmt.Sprintf(" %.1fs", diff)
				}
			}
			if s.Completed != nil {
				tm += " done"
			} else {
				isOpenStatus = true
			}
			fmt.Fprintf(p.w, "#%d %s%s%s\n", v.index, s.ID, bytes, tm)
		}
	}
	v.statusUpdates = map[string]struct{}{}

	for _, w := range v.warnings[v.warningIdx:] {
		fmt.Fprintf(p.w, "#%d WARN: %s\n", v.index, w.Short)
		v.warningIdx++
	}

	for i, l := range v.logs {
		if i == 0 {
			l = l[v.logsOffset:]
		}
		fmt.Fprintf(p.w, "%s", []byte(l))
		if i != len(v.logs)-1 || !v.logsPartial {
			fmt.Fprintln(p.w, "")
		}
		if v.logsBuffer == nil {
			v.logsBuffer = ring.New(logsBufferSize)
		}
		v.logsBuffer.Value = l
		if !v.logsPartial {
			v.logsBuffer = v.logsBuffer.Next()
		}
	}

	if len(v.logs) > 0 {
		if v.logsPartial {
			v.logs = v.logs[len(v.logs)-1:]
			v.logsOffset = len(v.logs[0])
		} else {
			v.logs = nil
			v.logsOffset = 0
		}
	}

	p.current = dgst
	if v.isCompleted() && !isOpenStatus {
		p.current = ""
		v.count = 0

		if v.Error != "" {
			if v.logsPartial {
				fmt.Fprintln(p.w, "")
			}
			if strings.HasSuffix(v.Error, context.Canceled.Error()) {
				fmt.Fprintf(p.w, "#%d CANCELED\n", v.index)
			} else {
				fmt.Fprintf(p.w, "#%d ERROR: %s\n", v.index, v.Error)
			}
		} else if v.Cached {
			fmt.Fprintf(p.w, "#%d CACHED\n", v.index)
		} else {
			tm := ""
			var ivals []interval
			for _, ival := range v.intervals {
				ivals = append(ivals, ival)
			}
			ivals = mergeIntervals(ivals)
			if len(ivals) > 0 {
				var dt float64
				for _, ival := range ivals {
					dt += ival.duration().Seconds()
				}
				tm = fmt.Sprintf(" %.1fs", dt)
			}
			fmt.Fprintf(p.w, "#%d DONE%s\n", v.index, tm)
		}
	}

	delete(t.updates, dgst)
}

func sortCompleted(t *trace, m map[digest.Digest]struct{}) []digest.Digest {
	out := make([]digest.Digest, 0, len(m))
	for k := range m {
		out = append(out, k)
	}
	sort.Slice(out, func(i, j int) bool {
		vtxi := t.byDigest[out[i]]
		vtxj := t.byDigest[out[j]]
		return vtxi.mostRecentInterval().stop.Before(*vtxj.mostRecentInterval().stop)
	})
	return out
}

func (p *textMux) print(t *trace) {
	completed := map[digest.Digest]struct{}{}
	rest := map[digest.Digest]struct{}{}

	for dgst := range t.updates {
		v, ok := t.byDigest[dgst]
		if !ok {
			continue
		}
		if v.ProgressGroup != nil || v.hidden {
			// skip vtxs in a group (they are merged into a single vtx) and hidden ones
			continue
		}
		if v.isCompleted() {
			completed[dgst] = struct{}{}
		} else {
			rest[dgst] = struct{}{}
		}
	}

	current := p.current

	// items that have completed need to be printed first
	if _, ok := completed[current]; ok {
		p.printVtx(t, current)
	}

	for _, dgst := range sortCompleted(t, completed) {
		if dgst != current {
			p.printVtx(t, dgst)
		}
	}

	if len(rest) == 0 {
		if current != "" {
			if v := t.byDigest[current]; v.isStarted() && !v.isCompleted() {
				return
			}
		}
		// make any open vertex active
		for dgst, v := range t.byDigest {
			if v.isStarted() && !v.isCompleted() {
				p.printVtx(t, dgst)
				return
			}
		}
		return
	}

	// now print the active one
	if _, ok := rest[current]; ok {
		p.printVtx(t, current)
	}

	stats := map[digest.Digest]*vtxStat{}
	now := time.Now()
	sum := 0.0
	var max digest.Digest
	if current != "" {
		rest[current] = struct{}{}
	}
	for dgst := range rest {
		v, ok := t.byDigest[dgst]
		if !ok {
			continue
		}
		tm := now.Sub(*v.lastBlockTime)
		speed := float64(v.count) / tm.Seconds()
		overLimit := tm > maxDelay && dgst != current
		stats[dgst] = &vtxStat{blockTime: tm, speed: speed, overLimit: overLimit}
		sum += speed
		if overLimit || max == "" || stats[max].speed < speed {
			max = dgst
		}
	}
	for dgst := range stats {
		stats[dgst].share = stats[dgst].speed / sum
	}

	if _, ok := completed[current]; ok || current == "" {
		p.printVtx(t, max)
		return
	}

	// show items that were hidden
	for dgst := range rest {
		if stats[dgst].overLimit {
			p.printVtx(t, dgst)
			return
		}
	}

	// fair split between vertexes
	if 1.0/(1.0-stats[current].share)*antiFlicker.Seconds() < stats[current].blockTime.Seconds() {
		p.printVtx(t, max)
		return
	}
}

type vtxStat struct {
	blockTime time.Duration
	speed     float64
	share     float64
	overLimit bool
}

func limitString(s string, l int) string {
	if len(s) > l {
		return s[:l] + "..."
	}
	return s
}
<commit_msg>progressui: fix printing of hidden vertexes.<commit_after>package progressui

import (
	"container/ring"
	"context"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
	"time"

	digest "github.com/opencontainers/go-digest"
	"github.com/tonistiigi/units"
)

const antiFlicker = 5 * time.Second
const maxDelay = 10 * time.Second
const minTimeDelta = 5 * time.Second
const minProgressDelta = 0.05 // %

const logsBufferSize = 10

type lastStatus struct {
	Current   int64
	Timestamp time.Time
}

type textMux struct {
	w         io.Writer
	current   digest.Digest
	last      map[string]lastStatus
	notFirst  bool
	nextIndex int
}

func (p *textMux) printVtx(t *trace, dgst digest.Digest) {
	if p.last == nil {
		p.last = make(map[string]lastStatus)
	}

	v, ok := t.byDigest[dgst]
	if !ok {
		return
	}

	if v.index == 0 {
		p.nextIndex++
		v.index = p.nextIndex
	}

	if dgst != p.current {
		if p.current != "" {
			old := t.byDigest[p.current]
			if old.logsPartial {
				fmt.Fprintln(p.w, "")
			}
			old.logsOffset = 0
			old.count = 0
			fmt.Fprintf(p.w, "#%d ...\n", old.index)
		}

		if p.notFirst {
			fmt.Fprintln(p.w, "")
		} else {
			p.notFirst = true
		}

		if os.Getenv("PROGRESS_NO_TRUNC") == "0" {
			fmt.Fprintf(p.w, "#%d %s\n", v.index, limitString(v.Name, 72))
		} else {
			fmt.Fprintf(p.w, "#%d %s\n", v.index, v.Name)
		}
	}

	if len(v.events) != 0 {
		v.logsOffset = 0
	}
	for _, ev := range v.events {
		fmt.Fprintf(p.w, "#%d %s\n", v.index, ev)
	}
	v.events = v.events[:0]

	isOpenStatus := false // remote cache loading can currently produce status updates without active vertex
	for _, s := range v.statuses {
		if _, ok := v.statusUpdates[s.ID]; ok {
			doPrint := true

			if last, ok := p.last[s.ID]; ok && s.Completed == nil {
				var progressDelta float64
				if s.Total > 0 {
					progressDelta = float64(s.Current-last.Current) / float64(s.Total)
				}
				timeDelta := s.Timestamp.Sub(last.Timestamp)
				if progressDelta < minProgressDelta && timeDelta < minTimeDelta {
					doPrint = false
				}
			}

			if !doPrint {
				continue
			}

			p.last[s.ID] = lastStatus{
				Timestamp: s.Timestamp,
				Current:   s.Current,
			}

			var bytes string
			if s.Total != 0 {
				bytes = fmt.Sprintf(" %.2f / %.2f", units.Bytes(s.Current), units.Bytes(s.Total))
			} else if s.Current != 0 {
				bytes = fmt.Sprintf(" %.2f", units.Bytes(s.Current))
			}
			var tm string
			endTime := s.Timestamp
			if s.Completed != nil {
				endTime = *s.Completed
			}
			if s.Started != nil {
				diff := endTime.Sub(*s.Started).Seconds()
				if diff > 0.01 {
					tm = fmt.Sprintf(" %.1fs", diff)
				}
			}
			if s.Completed != nil {
				tm += " done"
			} else {
				isOpenStatus = true
			}
			fmt.Fprintf(p.w, "#%d %s%s%s\n", v.index, s.ID, bytes, tm)
		}
	}
	v.statusUpdates = map[string]struct{}{}

	for _, w := range v.warnings[v.warningIdx:] {
		fmt.Fprintf(p.w, "#%d WARN: %s\n", v.index, w.Short)
		v.warningIdx++
	}

	for i, l := range v.logs {
		if i == 0 {
			l = l[v.logsOffset:]
		}
		fmt.Fprintf(p.w, "%s", []byte(l))
		if i != len(v.logs)-1 || !v.logsPartial {
			fmt.Fprintln(p.w, "")
		}
		if v.logsBuffer == nil {
			v.logsBuffer = ring.New(logsBufferSize)
		}
		v.logsBuffer.Value = l
		if !v.logsPartial {
			v.logsBuffer = v.logsBuffer.Next()
		}
	}

	if len(v.logs) > 0 {
		if v.logsPartial {
			v.logs = v.logs[len(v.logs)-1:]
			v.logsOffset = len(v.logs[0])
		} else {
			v.logs = nil
			v.logsOffset = 0
		}
	}

	p.current = dgst
	if v.isCompleted() && !isOpenStatus {
		p.current = ""
		v.count = 0

		if v.Error != "" {
			if v.logsPartial {
				fmt.Fprintln(p.w, "")
			}
			if strings.HasSuffix(v.Error, context.Canceled.Error()) {
				fmt.Fprintf(p.w, "#%d CANCELED\n", v.index)
			} else {
				fmt.Fprintf(p.w, "#%d ERROR: %s\n", v.index, v.Error)
			}
		} else if v.Cached {
			fmt.Fprintf(p.w, "#%d CACHED\n", v.index)
		} else {
			tm := ""
			var ivals []interval
			for _, ival := range v.intervals {
				ivals = append(ivals, ival)
			}
			ivals = mergeIntervals(ivals)
			if len(ivals) > 0 {
				var dt float64
				for _, ival := range ivals {
					dt += ival.duration().Seconds()
				}
				tm = fmt.Sprintf(" %.1fs", dt)
			}
			fmt.Fprintf(p.w, "#%d DONE%s\n", v.index, tm)
		}
	}

	delete(t.updates, dgst)
}

func sortCompleted(t *trace, m map[digest.Digest]struct{}) []digest.Digest {
	out := make([]digest.Digest, 0, len(m))
	for k := range m {
		out = append(out, k)
	}
	sort.Slice(out, func(i, j int) bool {
		vtxi := t.byDigest[out[i]]
		vtxj := t.byDigest[out[j]]
		return vtxi.mostRecentInterval().stop.Before(*vtxj.mostRecentInterval().stop)
	})
	return out
}

func (p *textMux) print(t *trace) {
	completed := map[digest.Digest]struct{}{}
	rest := map[digest.Digest]struct{}{}

	for dgst := range t.updates {
		v, ok := t.byDigest[dgst]
		if !ok {
			continue
		}
		if v.ProgressGroup != nil || v.hidden {
			// skip vtxs in a group (they are merged into a single vtx) and hidden ones
			continue
		}
		if v.isCompleted() {
			completed[dgst] = struct{}{}
		} else {
			rest[dgst] = struct{}{}
		}
	}

	current := p.current

	// items that have completed need to be printed first
	if _, ok := completed[current]; ok {
		p.printVtx(t, current)
	}

	for _, dgst := range sortCompleted(t, completed) {
		if dgst != current {
			p.printVtx(t, dgst)
		}
	}

	if len(rest) == 0 {
		if current != "" {
			if v := t.byDigest[current]; v.isStarted() && !v.isCompleted() {
				return
			}
		}
		// make any open vertex active
		for dgst, v := range t.byDigest {
			if v.isStarted() && !v.isCompleted() && v.ProgressGroup == nil && !v.hidden {
				p.printVtx(t, dgst)
				return
			}
		}
		return
	}

	// now print the active one
	if _, ok := rest[current]; ok {
		p.printVtx(t, current)
	}

	stats := map[digest.Digest]*vtxStat{}
	now := time.Now()
	sum := 0.0
	var max digest.Digest
	if current != "" {
		rest[current] = struct{}{}
	}
	for dgst := range rest {
		v, ok := t.byDigest[dgst]
		if !ok {
			continue
		}
		if v.lastBlockTime == nil {
			// shouldn't happen, but not worth crashing over
			continue
		}
		tm := now.Sub(*v.lastBlockTime)
		speed := float64(v.count) / tm.Seconds()
		overLimit := tm > maxDelay && dgst != current
		stats[dgst] = &vtxStat{blockTime: tm, speed: speed, overLimit: overLimit}
		sum += speed
		if overLimit || max == "" || stats[max].speed < speed {
			max = dgst
		}
	}
	for dgst := range stats {
		stats[dgst].share = stats[dgst].speed / sum
	}

	if _, ok := completed[current]; ok || current == "" {
		p.printVtx(t, max)
		return
	}

	// show items that were hidden
	for dgst := range rest {
		if stats[dgst].overLimit {
			p.printVtx(t, dgst)
			return
		}
	}

	// fair split between vertexes
	if 1.0/(1.0-stats[current].share)*antiFlicker.Seconds() < stats[current].blockTime.Seconds() {
		p.printVtx(t, max)
		return
	}
}

type vtxStat struct {
	blockTime time.Duration
	speed     float64
	share     float64
	overLimit bool
}

func limitString(s string, l int) string {
	if len(s) > l {
		return s[:l] + "..."
	}
	return s
}
<|endoftext|>


<commit_before>package consul

import (
	"fmt"
	"strings"

	"github.com/hashicorp/consul/api"
	"github.com/micro/go-micro/config/encoder"
)

type jsonValue interface {
	Value() interface{}
	Decode(encoder.Encoder, []byte) (jsonValue, error)
}
type jsonArrayValue []interface{}
type jsonMapValue map[string]interface{}

func (a jsonArrayValue) Value() interface{} { return a }
func (a jsonArrayValue) Decode(e encoder.Encoder, b []byte) (jsonValue, error) {
	v := jsonArrayValue{}
	err := e.Decode(b, &v)
	return v, err
}
func (m jsonMapValue) Value() interface{} { return m }
func (m jsonMapValue) Decode(e encoder.Encoder, b []byte) (jsonValue, error) {
	v := jsonMapValue{}
	err := e.Decode(b, &v)
	return v, err
}

func makeMap(e encoder.Encoder, kv api.KVPairs, stripPrefix string) (map[string]interface{}, error) {

	data := make(map[string]interface{})

	// consul guarantees lexicographic order, so no need to sort
	for _, v := range kv {
		pathString := strings.TrimPrefix(strings.TrimPrefix(v.Key, stripPrefix), "/")
		if pathString == "" {
			continue
		}
		var val jsonValue
		var err error

		// ensure a valid value is stored at this location
		if len(v.Value) > 0 {
			// check whether this is an array
			if v.Value[0] == 91 && v.Value[len(v.Value)-1] == 93 {
				val = jsonArrayValue{}
				if val, err = val.Decode(e, v.Value); err != nil {
					return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err)
				}
			} else {
				val = jsonMapValue{}
				if val, err = val.Decode(e, v.Value); err != nil {
					return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err)
				}
			}
		}

		target := data
		path := strings.Split(pathString, "/")
		// find (or create) the leaf node we want to put this value at
		for _, dir := range path[:len(path)-1] {
			if _, ok := target[dir]; !ok {
				target[dir] = make(map[string]interface{})
			}
			target = target[dir].(map[string]interface{})
		}

		leafDir := path[len(path)-1]

		// copy over the keys from the value
		switch val.(type) {
		case jsonArrayValue:
			target[leafDir] = val.Value()
		case jsonMapValue:
			target[leafDir] = make(map[string]interface{})
			target = target[leafDir].(map[string]interface{})
			mapv := val.Value().(jsonMapValue)
			for k := range mapv {
				target[k] = mapv[k]
			}
		}
	}

	return data, nil
}
<commit_msg>variable rename to abstract encoder<commit_after>package consul

import (
	"fmt"
	"strings"

	"github.com/hashicorp/consul/api"
	"github.com/micro/go-micro/config/encoder"
)

type configValue interface {
	Value() interface{}
	Decode(encoder.Encoder, []byte) error
}
type configArrayValue struct {
	v []interface{}
}

func (a *configArrayValue) Value() interface{} { return a.v }
func (a *configArrayValue) Decode(e encoder.Encoder, b []byte) error {
	return e.Decode(b, &a.v)
}

type configMapValue struct {
	v map[string]interface{}
}

func (m *configMapValue) Value() interface{} { return m.v }
func (m *configMapValue) Decode(e encoder.Encoder, b []byte) error {
	return e.Decode(b, &m.v)
}

func makeMap(e encoder.Encoder, kv api.KVPairs, stripPrefix string) (map[string]interface{}, error) {

	data := make(map[string]interface{})

	// consul guarantees lexicographic order, so no need to sort
	for _, v := range kv {
		pathString := strings.TrimPrefix(strings.TrimPrefix(v.Key, stripPrefix), "/")
		if pathString == "" {
			continue
		}
		var val configValue
		var err error

		// ensure a valid value is stored at this location
		if len(v.Value) > 0 {
			// try to decode into map value or array value
			arrayV := &configArrayValue{v: []interface{}{}}
			mapV := &configMapValue{v: map[string]interface{}{}}
			switch {
			case arrayV.Decode(e, v.Value) == nil:
				val = arrayV
			case mapV.Decode(e, v.Value) == nil:
				val = mapV
			default:
				return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err)
			}
		}

		target := data
		path := strings.Split(pathString, "/")
		// find (or create) the leaf node we want to put this value at
		for _, dir := range path[:len(path)-1] {
			if _, ok := target[dir]; !ok {
				target[dir] = make(map[string]interface{})
			}
			target = target[dir].(map[string]interface{})
		}

		leafDir := path[len(path)-1]

		// copy over the keys from the value
		switch val.(type) {
		case *configArrayValue:
			target[leafDir] = val.Value()
		case *configMapValue:
			target[leafDir] = make(map[string]interface{})
			target = target[leafDir].(map[string]interface{})
			mapv := val.Value().(map[string]interface{})
			for k := range mapv {
				target[k] = mapv[k]
			}
		}
	}

	return data, nil
}
<|endoftext|>


<commit_before>package nameserver

import (
	. "github.com/weaveworks/weave/common"
	wt "github.com/weaveworks/weave/testing"
	"net"
	"testing"
)

func TestAddrs(t *testing.T) {
	InitDefaultLogging(testing.Verbose())

	ip, err := addrToIPv4("10.13.12.11")
	wt.AssertNoErr(t, err)
	wt.AssertTrue(t, net.ParseIP("10.13.12.11").Equal(ip.toNetIP()), "IP")

	ip, err = raddrToIPv4("11.12.13.10.in-addr.arpa.")
	wt.AssertNoErr(t, err)
	wt.AssertTrue(t, net.ParseIP("10.13.12.11").Equal(ip.toNetIP()), "IP")

	// some malformed addresses
	ip, err = addrToIPv4("10.13.12")
	wt.AssertTrue(t, err != nil, "when parsing malformed address")
	ip, err = addrToIPv4("10.13.AA.12")
	wt.AssertTrue(t, err != nil, "when parsing malformed address")
	ip, err = raddrToIPv4("11.12.13.10.in-axxx.arpa.")
	wt.AssertTrue(t, err != nil, "when parsing malformed address")
	ip, err = raddrToIPv4("11.12.13.10.in-addr")
	wt.AssertTrue(t, err != nil, "when parsing malformed address")
}
<commit_msg>Minor: logging<commit_after>package nameserver

import (
	. "github.com/weaveworks/weave/common"
	wt "github.com/weaveworks/weave/testing"
	"net"
	"testing"
)

func TestAddrs(t *testing.T) {
	InitDefaultLogging(testing.Verbose())
	Info.Println("TestAddrs starting")

	ip, err := addrToIPv4("10.13.12.11")
	wt.AssertNoErr(t, err)
	wt.AssertTrue(t, net.ParseIP("10.13.12.11").Equal(ip.toNetIP()), "IP")

	ip, err = raddrToIPv4("11.12.13.10.in-addr.arpa.")
	wt.AssertNoErr(t, err)
	wt.AssertTrue(t, net.ParseIP("10.13.12.11").Equal(ip.toNetIP()), "IP")

	// some malformed addresses
	ip, err = addrToIPv4("10.13.12")
	wt.AssertTrue(t, err != nil, "when parsing malformed address")
	ip, err = addrToIPv4("10.13.AA.12")
	wt.AssertTrue(t, err != nil, "when parsing malformed address")
	ip, err = raddrToIPv4("11.12.13.10.in-axxx.arpa.")
	wt.AssertTrue(t, err != nil, "when parsing malformed address")
	ip, err = raddrToIPv4("11.12.13.10.in-addr")
	wt.AssertTrue(t, err != nil, "when parsing malformed address")
}
<|endoftext|>


<commit_before>package nameserver

import (
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/weaveworks/weave/net/address"
	"github.com/weaveworks/weave/router"
)

func TestAdd(t *testing.T) {
	oldNow := now
	defer func() { now = oldNow }()
	now = func() int64 { return 1234 }

	entries := Entries{}
	entries.add("A", "", router.UnknownPeerName, address.Address(0))
	expected := Entries{
		Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0)},
	}
	require.Equal(t, entries, expected)

	entries.tombstone(router.UnknownPeerName, func(e *Entry) bool { return e.Hostname == "A" })
	expected = Entries{
		Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0), Version: 1, Tombstone: 1234},
	}
	require.Equal(t, entries, expected)

	entries.add("A", "", router.UnknownPeerName, address.Address(0))
	expected = Entries{
		Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0), Version: 2},
	}
	require.Equal(t, entries, expected)
}

func TestMerge(t *testing.T) {
	e1 := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "C"},
		Entry{Hostname: "D"},
		Entry{Hostname: "F"},
	}

	e2 := Entries{
		Entry{Hostname: "B"},
		Entry{Hostname: "E"},
		Entry{Hostname: "F"},
	}

	diff := e1.merge(e2)
	expectedDiff := Entries{
		Entry{Hostname: "B"},
		Entry{Hostname: "E"},
	}
	require.Equal(t, expectedDiff, diff)

	expected := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "B"},
		Entry{Hostname: "C"},
		Entry{Hostname: "D"},
		Entry{Hostname: "E"},
		Entry{Hostname: "F"},
	}
	require.Equal(t, expected, e1)

	diff = e1.merge(e1)
	require.Equal(t, Entries{}, diff)
}

func TestOldMerge(t *testing.T) {
	e1 := Entries{Entry{Hostname: "A", Version: 0}}
	diff := e1.merge(Entries{Entry{Hostname: "A", Version: 1}})
	require.Equal(t, Entries{Entry{Hostname: "A", Version: 1}}, diff)
	require.Equal(t, Entries{Entry{Hostname: "A", Version: 1}}, e1)

	diff = e1.merge(Entries{Entry{Hostname: "A", Version: 0}})
	require.Equal(t, Entries{}, diff)
	require.Equal(t, Entries{Entry{Hostname: "A", Version: 1}}, e1)
}

func TestTombstone(t *testing.T) {
	oldNow := now
	defer func() { now = oldNow }()
	now = func() int64 { return 1234 }

	es := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "B"},
	}

	es.tombstone(router.UnknownPeerName, func(e *Entry) bool {
		return e.Hostname == "B"
	})
	expected := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "B", Version: 1, Tombstone: 1234},
	}
	require.Equal(t, expected, es)
}

func TestDelete(t *testing.T) {
	es := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "B"},
	}

	es.filter(func(e *Entry) bool {
		return e.Hostname != "A"
	})
	expected := Entries{
		Entry{Hostname: "B"},
	}
	require.Equal(t, expected, es)
}

func TestLookup(t *testing.T) {
	es := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "B", ContainerID: "bar"},
		Entry{Hostname: "B", ContainerID: "foo"},
		Entry{Hostname: "C"},
	}

	have := es.lookup("B")
	want := Entries{
		Entry{Hostname: "B", ContainerID: "bar"},
		Entry{Hostname: "B", ContainerID: "foo"},
	}
	require.Equal(t, have, want)
}
<commit_msg>Add unit test to check outbound mixed-case merging<commit_after>package nameserver

import (
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/weaveworks/weave/net/address"
	"github.com/weaveworks/weave/router"
)

func TestAdd(t *testing.T) {
	oldNow := now
	defer func() { now = oldNow }()
	now = func() int64 { return 1234 }

	entries := Entries{}
	entries.add("A", "", router.UnknownPeerName, address.Address(0))
	expected := Entries{
		Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0)},
	}
	require.Equal(t, entries, expected)

	entries.tombstone(router.UnknownPeerName, func(e *Entry) bool { return e.Hostname == "A" })
	expected = Entries{
		Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0), Version: 1, Tombstone: 1234},
	}
	require.Equal(t, entries, expected)

	entries.add("A", "", router.UnknownPeerName, address.Address(0))
	expected = Entries{
		Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0), Version: 2},
	}
	require.Equal(t, entries, expected)
}

func TestMerge(t *testing.T) {
	e1 := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "C"},
		Entry{Hostname: "D"},
		Entry{Hostname: "F"},
	}

	e2 := Entries{
		Entry{Hostname: "B"},
		Entry{Hostname: "E"},
		Entry{Hostname: "F"},
	}

	diff := e1.merge(e2)
	expectedDiff := Entries{
		Entry{Hostname: "B"},
		Entry{Hostname: "E"},
	}
	require.Equal(t, expectedDiff, diff)

	expected := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "B"},
		Entry{Hostname: "C"},
		Entry{Hostname: "D"},
		Entry{Hostname: "E"},
		Entry{Hostname: "F"},
	}
	require.Equal(t, expected, e1)

	diff = e1.merge(e1)
	require.Equal(t, Entries{}, diff)
}

func TestOldMerge(t *testing.T) {
	e1 := Entries{Entry{Hostname: "A", Version: 0}}
	diff := e1.merge(Entries{Entry{Hostname: "A", Version: 1}})
	require.Equal(t, Entries{Entry{Hostname: "A", Version: 1}}, diff)
	require.Equal(t, Entries{Entry{Hostname: "A", Version: 1}}, e1)

	diff = e1.merge(Entries{Entry{Hostname: "A", Version: 0}})
	require.Equal(t, Entries{}, diff)
	require.Equal(t, Entries{Entry{Hostname: "A", Version: 1}}, e1)
}

func TestTombstone(t *testing.T) {
	oldNow := now
	defer func() { now = oldNow }()
	now = func() int64 { return 1234 }

	es := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "B"},
	}

	es.tombstone(router.UnknownPeerName, func(e *Entry) bool {
		return e.Hostname == "B"
	})
	expected := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "B", Version: 1, Tombstone: 1234},
	}
	require.Equal(t, expected, es)
}

func TestDelete(t *testing.T) {
	es := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "B"},
	}

	es.filter(func(e *Entry) bool {
		return e.Hostname != "A"
	})
	expected := Entries{
		Entry{Hostname: "B"},
	}
	require.Equal(t, expected, es)
}

func TestLookup(t *testing.T) {
	es := Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "B", ContainerID: "bar"},
		Entry{Hostname: "B", ContainerID: "foo"},
		Entry{Hostname: "C"},
	}

	have := es.lookup("B")
	want := Entries{
		Entry{Hostname: "B", ContainerID: "bar"},
		Entry{Hostname: "B", ContainerID: "foo"},
	}
	require.Equal(t, have, want)
}

func TestGossipDataMerge(t *testing.T) {
	g1 := GossipData{Entries: Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "c"},
		Entry{Hostname: "D"},
		Entry{Hostname: "f"},
	}}

	g2 := GossipData{Entries: Entries{
		Entry{Hostname: "B"},
		Entry{Hostname: "E"},
		Entry{Hostname: "f"},
	}}

	g1.Merge(&g2)

	expected := GossipData{Entries: Entries{
		Entry{Hostname: "A"},
		Entry{Hostname: "B"},
		Entry{Hostname: "c"},
		Entry{Hostname: "D"},
		Entry{Hostname: "E"},
		Entry{Hostname: "f"},
	}}

	require.Equal(t, expected, g1)
}
<|endoftext|>


<commit_before>/**
 * shorthand_test.go - tests for short package for handling shorthand
 * definition and expansion.
 *
 * @author R. S. Doiel, <rsdoiel@gmail.com>
 * copyright (c) 2015 all rights reserved.
 * Released under the BSD 2-Clause license
 */
package shorthand

import (
	"../ok"
	"strings"
	"testing"
)

// Test IsAssignment
func TestIsAssignment(t *testing.T) {
	validAssignments := []string{
		"@now := $(date)",
		"this := a valid assignment",
		"this; := is a valid assignment",
		"now; := $(date +\"%H:%M\");",
		"@here :< ./testme.md",
	}

	invalidAssignments := []string{
		"This is not an assignment",
		"this:=  is not a valid assignment",
		"nor :=is this a valid assignment",
	}

	for i := range validAssignments {
		if IsAssignment(validAssignments[i]) == false {
			t.Fatalf(validAssignments[i] + " should be a valid assignment.")
		}
	}

	for i := range invalidAssignments {
		if IsAssignment(invalidAssignments[i]) == true {
			t.Fatalf(invalidAssignments[i] + " should be an invalid assignment.")
		}
	}
}

// Test Assign
func TestAssign(t *testing.T) {
	Clear()
	validAssignments := []string{
		"@now := $(date)",
		"this := a valid assignment",
		"this; := is a valid assignment",
		"now; := $(date +\"%H:%M\");",
		"@new := Fred\n",
	}
	expectedMap := map[string]string{
		"@now":  "$(date)",
		"this":  "a valid assignment",
		"this;": "is a valid assignment",
		"now;":  "$(date +\"%H:%M\");",
		"@new":  "Fred",
	}

	for i := range validAssignments {
		if Assign(validAssignments[i]) == false {
			t.Fatalf(validAssignments[i] + " should be assigned.")
		}
	}

	for key, value := range expectedMap {
		expected, OK := Abbreviations[key]
		if !OK {
			t.Fatalf("Could not find the shorthand for " + key)
		}
		if expected != value {
			t.Fatalf("[" + expected + "] != [" + value + "]")
		}
	}
}

// Test Expand
func TestExpand(t *testing.T) {
	Clear()
	text := `
@me

This is some line that should not change.

8:00 - @now; some stuff

This "now" should not change. This "me" should not change.`

	expected := `
Fred

This is some line that should not change.

8:00 - 9:00; some stuff

This "now" should not change. This "me" should not change.`

	Assign("@me := Fred\n")
	Assign("@now := 9:00")
	result := Expand(text)
	if result != expected {
		t.Fatalf("Expected:\n\n" + expected + "\n\nReceived:\n\n" + result)
	}
}

// Test include file
func TestInclude(t *testing.T) {
	text := `
Today is @NOW.

Now add the testme.md to this.
-------------------------------
@TESTME
-------------------------------
Did it work?
`
	Assign("@NOW := 2015-07-04")
	expected := true
	results := HasAssignment("@NOW")
	ok.Ok(t, results == expected, "Should have @NOW assignment")
	Assign("@TESTME :< ./testme.md")
	results = HasAssignment("@TESTME")
	ok.Ok(t, results == expected, "Should have @TESTME assignment")
	resultText := Expand(text)
	l := len(text)
	ok.Ok(t, len(resultText) > l, "Should have more results: "+resultText)
	ok.Ok(t, strings.Contains(resultText, "A nimble webserver"), "Should have 'A nimble webserver' in "+resultText)
	ok.Ok(t, strings.Contains(resultText, "JSON"), "Should have 'JSON' in "+resultText)
}
<commit_msg>Added tests for shell output assignment in shorthand.<commit_after>/**
 * shorthand_test.go - tests for short package for handling shorthand
 * definition and expansion.
 *
 * @author R. S. Doiel, <rsdoiel@gmail.com>
 * copyright (c) 2015 all rights reserved.
 * Released under the BSD 2-Clause license
 */
package shorthand

import (
	"../ok"
	"strings"
	"testing"
)

// Test IsAssignment
func TestIsAssignment(t *testing.T) {
	validAssignments := []string{
		"@now := $(date)",
		"this := a valid assignment",
		"this; := is a valid assignment",
		"now; := $(date +\"%H:%M\");",
		"@here :< ./testme.md",
	}

	invalidAssignments := []string{
		"This is not an assignment",
		"this:=  is not a valid assignment",
		"nor :=is this a valid assignment",
	}

	for i := range validAssignments {
		if IsAssignment(validAssignments[i]) == false {
			t.Fatalf(validAssignments[i] + " should be a valid assignment.")
		}
	}

	for i := range invalidAssignments {
		if IsAssignment(invalidAssignments[i]) == true {
			t.Fatalf(invalidAssignments[i] + " should be an invalid assignment.")
		}
	}
}

// Test Assign
func TestAssign(t *testing.T) {
	Clear()
	validAssignments := []string{
		"@now := $(date)",
		"this := a valid assignment",
		"this; := is a valid assignment",
		"now; := $(date +\"%H:%M\");",
		"@new := Fred\n",
	}
	expectedMap := map[string]string{
		"@now":  "$(date)",
		"this":  "a valid assignment",
		"this;": "is a valid assignment",
		"now;":  "$(date +\"%H:%M\");",
		"@new":  "Fred",
	}

	for i := range validAssignments {
		if Assign(validAssignments[i]) == false {
			t.Fatalf(validAssignments[i] + " should be assigned.")
		}
	}

	for key, value := range expectedMap {
		expected, OK := Abbreviations[key]
		if !OK {
			t.Fatalf("Could not find the shorthand for " + key)
		}
		if expected != value {
			t.Fatalf("[" + expected + "] != [" + value + "]")
		}
	}
}

// Test Expand
func TestExpand(t *testing.T) {
	Clear()
	text := `
@me

This is some line that should not change.

8:00 - @now; some stuff

This "now" should not change. This "me" should not change.`

	expected := `
Fred

This is some line that should not change.

8:00 - 9:00; some stuff

This "now" should not change. This "me" should not change.`

	Assign("@me := Fred\n")
	Assign("@now := 9:00")
	result := Expand(text)
	if result != expected {
		t.Fatalf("Expected:\n\n" + expected + "\n\nReceived:\n\n" + result)
	}
}

// Test include file
func TestInclude(t *testing.T) {
	text := `
Today is @NOW.

Now add the testme.md to this.
-------------------------------
@TESTME
-------------------------------
Did it work?
`
	Assign("@NOW := 2015-07-04")
	expected := true
	results := HasAssignment("@NOW")
	ok.Ok(t, results == expected, "Should have @NOW assignment")
	Assign("@TESTME :< ./testme.md")
	results = HasAssignment("@TESTME")
	ok.Ok(t, results == expected, "Should have @TESTME assignment")
	resultText := Expand(text)
	l := len(text)
	ok.Ok(t, len(resultText) > l, "Should have more results: "+resultText)
	ok.Ok(t, strings.Contains(resultText, "A nimble webserver"), "Should have 'A nimble webserver' in "+resultText)
	ok.Ok(t, strings.Contains(resultText, "JSON"), "Should have 'JSON' in "+resultText)
}

func TestShellAssignment(t *testing.T) {
	Assign("@ECHO :! echo 'Hello World!'")
	expected := true
	results := HasAssignment("@ECHO")
	ok.Ok(t, results == expected, "Should have @ECHO assignment")
	expectedText := "Hello World!"
	resultText := Expand("@ECHO")
	l := len(resultText)
	ok.Ok(t, l == len(expectedText), "Should have expected length for @ECHO")
	ok.Ok(t, strings.Contains(resultText, expectedText), "Should have matching text for @ECHO")
}
<|endoftext|>


<commit_before>// Copyright (c) 2020-2021 Sippy Software, Inc. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package sippy_sshaken

import (
    "crypto/ecdsa"
    "crypto/sha256"
    "crypto/x509"
    "encoding/json"
    "encoding/pem"
    "errors"
    "fmt"
    "math/big"
    "strings"
    "time"

    "sippy/utils"
)

type Verifier interface {
    Verify(passport *sshaken_passport, cert_buf []byte, orig_tn_p, dest_tn_p string, date_ts time.Time) error
}

type sshaken_verifier struct {
    roots       *x509.CertPool
}

func NewVerifier(chain_buf []byte) (*sshaken_verifier, error) {
    self := &sshaken_verifier{
        roots   : x509.NewCertPool(),
    }
    if ! self.roots.AppendCertsFromPEM(chain_buf) {
        return nil, errors.New("error parsing the root certificates")
    }
    return self, nil
}

func (self *sshaken_verifier) Verify(passport *sshaken_passport, cert_buf []byte, orig_tn_p, dest_tn_p string, date_ts time.Time) error {
    if passport.ppt_hdr_param != "shaken"{
        return errors.New("Unsupported 'ppt' extension")
    }
    if passport.alg_hdr_param != "" && passport.alg_hdr_param != "ES256" {
        return errors.New("Unsupported 'alg'")
    }
    err := passport.check_claims()
    if err != nil {
        return err
    }
    now := time.Now()
    if now.Sub(date_ts) > VERIFY_DATE_FRESHNESS {
        return errors.New("Date header value is older than local policy")
    }
    orig_tn_p = cleanup(orig_tn_p)
    dest_tn_p = cleanup(dest_tn_p)
    if passport.OrigTN() != orig_tn_p || passport.DestTN() != dest_tn_p {
        return errors.New("Signature would not verify successfully")
    }
    cert, err := load_cert(cert_buf)
    if err != nil {
        return err
    }
    check_cert_validity(cert, date_ts)
    err = self.validate_certificate(cert)
    if err != nil {
        return err
    }
    iat_ts := passport.Iat()
    if iat_ts != date_ts && now.Sub(iat_ts) > VERIFY_DATE_FRESHNESS {
        iat_ts = date_ts
    }
    return verify_signature(cert, passport, iat_ts, orig_tn_p, dest_tn_p)
}

func (self *sshaken_verifier) validate_certificate(cert *x509.Certificate) error {
    tn_ext_found := false
    for _, ext := range cert.Extensions {
        if ext.Id.Equal(TNAUTHLIST_EXT) {
            tn_ext_found = true
            break
        }
    }
    if ! tn_ext_found {
        return errors.New("The certificate misses TnAuthList extension")
    }
    opts := x509.VerifyOptions{
        Roots: self.roots,
    }
    chains, err := cert.Verify(opts)
    if err != nil {
        return err
    }
    if len(chains) == 0 {
        return errors.New("no matching root certificate")
    }
    return nil
}

func build_unsigned_pport(iat_ts time.Time, attest, cr_url, orig_tn, dest_tn, origid string) string {
    hdr := sshaken_header{
        Alg : "ES256",
        Ppt : "shaken",
        Typ : "passport",
        X5u : cr_url,
    }
    hdr_json_str, _ := json.Marshal(hdr)

    payload := sshaken_payload{
        Attest  : attest,
        Dest    : sshaken_dest{
            TN  : []string{ dest_tn },
        },
        Iat     : iat_ts.Unix(),
        Orig    : sshaken_orig{
            TN  : orig_tn,
        },
        Origid  : origid,
    }
    payload_json_str, _ := json.Marshal(payload)
    return sippy_utils.B64EncodeNoPad(hdr_json_str) + "." + sippy_utils.B64EncodeNoPad(payload_json_str)
}

func verify_signature(cert *x509.Certificate, passport *sshaken_passport, iat_ts time.Time, orig_tn, dest_tn string) error {
    if len(passport.signature) != 64 {
        return fmt.Errorf("Bad raw signature length %d, should be 64", len(passport.signature))
    }
    unsigned_buf := build_unsigned_pport(iat_ts, passport.Attest(), passport.X5u(), orig_tn, dest_tn, passport.Origid())
    r := big.NewInt(0).SetBytes(passport.signature[:32])
    s := big.NewInt(0).SetBytes(passport.signature[32:])
    hash := sha256.Sum256([]byte(unsigned_buf))
    pub_key, ok := cert.PublicKey.(*ecdsa.PublicKey)
    if ! ok {
        return errors.New("wrong public key")
    }
    if ! ecdsa.Verify(pub_key, hash[:], r, s) {
        return errors.New("verification failed")
    }
    return nil
}

func load_cert(cert_buf []byte) (*x509.Certificate, error) {
    block, _ := pem.Decode(cert_buf)
    cert, err := x509.ParseCertificate(block.Bytes)
    if err != nil {
        return nil, err
    }
    return cert, nil
}

func ParseIdentity(hdr_buf string) (*sshaken_passport, error) {
    arr := strings.SplitN(hdr_buf, ";", 2)
    if len(arr) != 2 {
        return nil, errors.New("no parameters in Identity")
    }
    hdr_arr := strings.Split(arr[0], ".")
    if len(hdr_arr) != 3 {
        return nil, errors.New("Bad signature")
    }
    params_arr := strings.Split(arr[1], ";")
    if len(params_arr) == 0 {
        return nil, errors.New("Header parameters missing")
    }
    passport := &sshaken_passport{}

    for _, param := range params_arr {
        p_arr := strings.SplitN(param, "=", 2)
        if len(p_arr) != 2 {
            continue
        }
        switch p_arr[0] {
        case "alg":
            passport.alg_hdr_param = strings.Trim(p_arr[1], "\"")
        case "ppt":
            passport.ppt_hdr_param = strings.Trim(p_arr[1], "\"")
        }
    }
    buf, err := sippy_utils.B64DecodeNoPad(hdr_arr[0])
    if err != nil {
        return nil, err
    }
    if err = json.Unmarshal(buf, &passport.Header); err != nil {
        return nil, err
    }
    buf, err = sippy_utils.B64DecodeNoPad(hdr_arr[1])
    if err != nil {
        return nil, err
    }
    if err = json.Unmarshal(buf, &passport.Payload); err != nil {
        return nil, err
    }
    passport.signature, err = sippy_utils.B64DecodeNoPad(hdr_arr[2])
    if err != nil {
        return nil, err
    }
    return passport, nil
}

func cleanup(in string) string {
    out := []byte{}
    for _, ch := range []byte(in) {
        switch ch {
        case '0': fallthrough
        case '1': fallthrough
        case '2': fallthrough
        case '3': fallthrough
        case '4': fallthrough
        case '5': fallthrough
        case '6': fallthrough
        case '7': fallthrough
        case '8': fallthrough
        case '9': fallthrough
        case '*': fallthrough
        case '#':
            out = append(out, ch)
        }
    }
    return string(out)
}
<commit_msg>Fix for malformed certificate and IAT check.<commit_after>// Copyright (c) 2020-2021 Sippy Software, Inc. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package sippy_sshaken

import (
    "crypto/ecdsa"
    "crypto/sha256"
    "crypto/x509"
    "encoding/json"
    "encoding/pem"
    "errors"
    "fmt"
    "math/big"
    "strings"
    "time"

    "sippy/utils"
)

type Verifier interface {
    Verify(passport *sshaken_passport, cert_buf []byte, orig_tn_p, dest_tn_p string, date_ts time.Time) error
}

type sshaken_verifier struct {
    roots       *x509.CertPool
}

func NewVerifier(chain_buf []byte) (*sshaken_verifier, error) {
    self := &sshaken_verifier{
        roots   : x509.NewCertPool(),
    }
    if ! self.roots.AppendCertsFromPEM(chain_buf) {
        return nil, errors.New("error parsing the root certificates")
    }
    return self, nil
}

func (self *sshaken_verifier) Verify(passport *sshaken_passport, cert_buf []byte, orig_tn_p, dest_tn_p string, date_ts time.Time) error {
    if passport.ppt_hdr_param != "shaken"{
        return errors.New("Unsupported 'ppt' extension")
    }
    if passport.alg_hdr_param != "" && passport.alg_hdr_param != "ES256" {
        return errors.New("Unsupported 'alg'")
    }
    err := passport.check_claims()
    if err != nil {
        return err
    }
    now := time.Now()
    if now.Sub(date_ts) > VERIFY_DATE_FRESHNESS {
        return errors.New("Date header value is older than local policy")
    }
    orig_tn_p = cleanup(orig_tn_p)
    dest_tn_p = cleanup(dest_tn_p)
    if passport.OrigTN() != orig_tn_p || passport.DestTN() != dest_tn_p {
        return errors.New("Signature would not verify successfully")
    }
    cert, err := load_cert(cert_buf)
    if err != nil {
        return err
    }
    check_cert_validity(cert, date_ts)
    err = self.validate_certificate(cert)
    if err != nil {
        return err
    }
    iat_ts := passport.Iat()
    diff := now.Sub(iat_ts)
    if diff < 0 {
        diff = -diff
    }
    if ! iat_ts.Equal(date_ts) && diff > VERIFY_DATE_FRESHNESS {
        iat_ts = date_ts
    }
    return verify_signature(cert, passport, iat_ts, orig_tn_p, dest_tn_p)
}

func (self *sshaken_verifier) validate_certificate(cert *x509.Certificate) error {
    tn_ext_found := false
    for _, ext := range cert.Extensions {
        if ext.Id.Equal(TNAUTHLIST_EXT) {
            tn_ext_found = true
            break
        }
    }
    if ! tn_ext_found {
        return errors.New("The certificate misses TnAuthList extension")
    }
    opts := x509.VerifyOptions{
        Roots: self.roots,
    }
    chains, err := cert.Verify(opts)
    if err != nil {
        return err
    }
    if len(chains) == 0 {
        return errors.New("no matching root certificate")
    }
    return nil
}

func build_unsigned_pport(iat_ts time.Time, attest, cr_url, orig_tn, dest_tn, origid string) string {
    hdr := sshaken_header{
        Alg : "ES256",
        Ppt : "shaken",
        Typ : "passport",
        X5u : cr_url,
    }
    hdr_json_str, _ := json.Marshal(hdr)

    payload := sshaken_payload{
        Attest  : attest,
        Dest    : sshaken_dest{
            TN  : []string{ dest_tn },
        },
        Iat     : iat_ts.Unix(),
        Orig    : sshaken_orig{
            TN  : orig_tn,
        },
        Origid  : origid,
    }
    payload_json_str, _ := json.Marshal(payload)
    return sippy_utils.B64EncodeNoPad(hdr_json_str) + "." + sippy_utils.B64EncodeNoPad(payload_json_str)
}

func verify_signature(cert *x509.Certificate, passport *sshaken_passport, iat_ts time.Time, orig_tn, dest_tn string) error {
    if len(passport.signature) != 64 {
        return fmt.Errorf("Bad raw signature length %d, should be 64", len(passport.signature))
    }
    unsigned_buf := build_unsigned_pport(iat_ts, passport.Attest(), passport.X5u(), orig_tn, dest_tn, passport.Origid())
    r := big.NewInt(0).SetBytes(passport.signature[:32])
    s := big.NewInt(0).SetBytes(passport.signature[32:])
    hash := sha256.Sum256([]byte(unsigned_buf))
    pub_key, ok := cert.PublicKey.(*ecdsa.PublicKey)
    if ! ok {
        return errors.New("wrong public key")
    }
    if ! ecdsa.Verify(pub_key, hash[:], r, s) {
        return errors.New("verification failed")
    }
    return nil
}

func load_cert(cert_buf []byte) (*x509.Certificate, error) {
    if len(cert_buf) == 0 {
        return nil, errors.New("empty certificate")
    }
    block, _ := pem.Decode(cert_buf)
    if block == nil {
        return nil, errors.New("error decoding a certificate")
    }
    cert, err := x509.ParseCertificate(block.Bytes)
    if err != nil {
        return nil, err
    }
    return cert, nil
}

func ParseIdentity(hdr_buf string) (*sshaken_passport, error) {
    arr := strings.SplitN(hdr_buf, ";", 2)
    if len(arr) != 2 {
        return nil, errors.New("no parameters in Identity")
    }
    hdr_arr := strings.Split(arr[0], ".")
    if len(hdr_arr) != 3 {
        return nil, errors.New("Bad signature")
    }
    params_arr := strings.Split(arr[1], ";")
    if len(params_arr) == 0 {
        return nil, errors.New("Header parameters missing")
    }
    passport := &sshaken_passport{}

    for _, param := range params_arr {
        p_arr := strings.SplitN(param, "=", 2)
        if len(p_arr) != 2 {
            continue
        }
        switch p_arr[0] {
        case "alg":
            passport.alg_hdr_param = strings.Trim(p_arr[1], "\"")
        case "ppt":
            passport.ppt_hdr_param = strings.Trim(p_arr[1], "\"")
        }
    }
    buf, err := sippy_utils.B64DecodeNoPad(hdr_arr[0])
    if err != nil {
        return nil, err
    }
    if err = json.Unmarshal(buf, &passport.Header); err != nil {
        return nil, err
    }
    buf, err = sippy_utils.B64DecodeNoPad(hdr_arr[1])
    if err != nil {
        return nil, err
    }
    if err = json.Unmarshal(buf, &passport.Payload); err != nil {
        return nil, err
    }
    passport.signature, err = sippy_utils.B64DecodeNoPad(hdr_arr[2])
    if err != nil {
        return nil, err
    }
    return passport, nil
}

func cleanup(in string) string {
    out := []byte{}
    for _, ch := range []byte(in) {
        switch ch {
        case '0': fallthrough
        case '1': fallthrough
        case '2': fallthrough
        case '3': fallthrough
        case '4': fallthrough
        case '5': fallthrough
        case '6': fallthrough
        case '7': fallthrough
        case '8': fallthrough
        case '9': fallthrough
        case '*': fallthrough
        case '#':
            out = append(out, ch)
        }
    }
    return string(out)
}
<|endoftext|>


<commit_before>// Copyright 2014 Ted Goddard. All rights reserved.
// Use of this source code is governed the Apache 2.0
// license that can be found in the LICENSE file.

package main

import "fmt"
import "net"
import "os"
import "bufio"
import "net/http"
import "websocket"
import "log"
import "fits"
import "encoding/json"

func main() {
	fmt.Println("Starting server")

    previousImagePath := ""
    currentImagePath := ""

    wsClientHTML :=
        "" +
            "" +
                "" +
            "" +
            "" +
            "" +
            "<button style='position:fixed;bottom:0;left:0' onclick='guide()'>GUIDE</button>" +
            "" +
        ""

    http.HandleFunc("/phdremote/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, wsClientHTML)
    })

    //only one websocket allowed for now
    var wsConn *websocket.Conn
    var phdWrite *bufio.Writer
    phdDone := make(chan bool)

    GuideWatch := func (conn *net.Conn)  {
        connRead := bufio.NewReader(*conn)
        status := ""
        var err error
        for (err == nil)  {
            status, err = connRead.ReadString('\n')
            log.Print(status)
            var phdMessage map[string]interface{}
            err = json.Unmarshal([]byte(status), &phdMessage)
            if (nil == err)  {
                if (nil != phdMessage["jsonrpc"]) {
                    log.Print("jsonrpc contents", status)
                    switch result := phdMessage["result"].(type)  {
                        case map[string]interface{}:
                            previousImagePath = currentImagePath
                            currentImagePath = result["filename"].(string)
                            if ("" != previousImagePath)  {
                                os.Remove(previousImagePath)
                            }
                        case float64:
                            log.Print("float64 jsonrpc result")
                    }
                }
                fmt.Println(phdMessage["jsonrpc"])
            }

            if (nil != wsConn)  {
                log.Print("writing to WebSocket")
                (*wsConn).Write([]byte(status))
            }
        }
        phdDone <- true
    }

    SocketWatch := func()  {
        var err error
        for (err == nil)  {
            var msg = make([]byte, 512)
            var n int
            n, err = wsConn.Read(msg)
            fmt.Printf("WEBSOCKET Received: %s.\n", msg[:n])
            if (nil != phdWrite)  {
                fmt.Fprintf(phdWrite, string(msg))
                phdWrite.Flush()
            }
        }
    }

    EchoServer := func(newConn *websocket.Conn) {
        log.Print("EchoServer started")
        wsConn = newConn
        go SocketWatch ()
        echoDone := <-phdDone
        if (echoDone)  {
            log.Print("EchoServer done")
       }
    }

    log.Print("websocket.Handler")
    wsHandler := websocket.Handler(EchoServer)
	http.Handle("/echo/", wsHandler)

    conn, err := net.Dial("tcp", "localhost:4400")
    if (err == nil) {
        phdWrite = bufio.NewWriter(conn)
        go GuideWatch (&conn)
    } else {
        log.Print("Unable to connect to PHD")
    }

    http.HandleFunc("/phdremote/cam.png", func(w http.ResponseWriter, r *http.Request) {
log.Print("returning png image")
        if (nil != phdWrite)  {
            fmt.Fprintf(phdWrite, "{\"method\":\"save_image\",\"id\":123}\n")
            phdWrite.Flush()
        }
        w.Header().Set("Content-Type", "image/png")
        momentaryImagePath := currentImagePath
        if ("" == momentaryImagePath)  {
            momentaryImagePath = "RCA.fit"
        }
        fits.Convert(momentaryImagePath, w)
    })

    log.Print("http.ListenAndServe")
    log.Fatal(http.ListenAndServe(":8080", nil))

}

<commit_msg>insane code to get click position on image #1<commit_after>// Copyright 2014 Ted Goddard. All rights reserved.
// Use of this source code is governed the Apache 2.0
// license that can be found in the LICENSE file.

package main

import "fmt"
import "net"
import "os"
import "bufio"
import "net/http"
import "websocket"
import "log"
import "fits"
import "encoding/json"

func main() {
	fmt.Println("Starting server")

    previousImagePath := ""
    currentImagePath := ""

    wsClientHTML :=
        "" +
            "" +
                "" +
            "" +
            "" +
            "" +
            "<button style='position:fixed;bottom:0;left:0' onclick='guide()'>GUIDE</button>" +
            "" +
        ""

    http.HandleFunc("/phdremote/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, wsClientHTML)
    })

    //only one websocket allowed for now
    var wsConn *websocket.Conn
    var phdWrite *bufio.Writer
    phdDone := make(chan bool)

    GuideWatch := func (conn *net.Conn)  {
        connRead := bufio.NewReader(*conn)
        status := ""
        var err error
        for (err == nil)  {
            status, err = connRead.ReadString('\n')
            log.Print(status)
            var phdMessage map[string]interface{}
            err = json.Unmarshal([]byte(status), &phdMessage)
            if (nil == err)  {
                if (nil != phdMessage["jsonrpc"]) {
                    log.Print("jsonrpc contents", status)
                    switch result := phdMessage["result"].(type)  {
                        case map[string]interface{}:
                            previousImagePath = currentImagePath
                            currentImagePath = result["filename"].(string)
                            if ("" != previousImagePath)  {
                                os.Remove(previousImagePath)
                            }
                        case float64:
                            log.Print("float64 jsonrpc result")
                    }
                }
                fmt.Println(phdMessage["jsonrpc"])
            }

            if (nil != wsConn)  {
                log.Print("writing to WebSocket")
                (*wsConn).Write([]byte(status))
            }
        }
        phdDone <- true
    }

    SocketWatch := func()  {
        var err error
        for (err == nil)  {
            var msg = make([]byte, 512)
            var n int
            n, err = wsConn.Read(msg)
            fmt.Printf("WEBSOCKET Received: %s.\n", msg[:n])
            if (nil != phdWrite)  {
                fmt.Fprintf(phdWrite, string(msg))
                phdWrite.Flush()
            }
        }
    }

    EchoServer := func(newConn *websocket.Conn) {
        log.Print("EchoServer started")
        wsConn = newConn
        go SocketWatch ()
        echoDone := <-phdDone
        if (echoDone)  {
            log.Print("EchoServer done")
       }
    }

    log.Print("websocket.Handler")
    wsHandler := websocket.Handler(EchoServer)
	http.Handle("/echo/", wsHandler)

    conn, err := net.Dial("tcp", "localhost:4400")
    if (err == nil) {
        phdWrite = bufio.NewWriter(conn)
        go GuideWatch (&conn)
    } else {
        log.Print("Unable to connect to PHD")
    }

    http.HandleFunc("/phdremote/cam.png", func(w http.ResponseWriter, r *http.Request) {
log.Print("returning png image")
        if (nil != phdWrite)  {
            fmt.Fprintf(phdWrite, "{\"method\":\"save_image\",\"id\":123}\n")
            phdWrite.Flush()
        }
        w.Header().Set("Content-Type", "image/png")
        momentaryImagePath := currentImagePath
        if ("" == momentaryImagePath)  {
            momentaryImagePath = "RCA.fit"
        }
        fits.Convert(momentaryImagePath, w)
    })

    log.Print("http.ListenAndServe")
    log.Fatal(http.ListenAndServe(":8080", nil))

}

<|endoftext|>


<commit_before>package actions

import (
	"github.com/PuerkitoBio/goquery"
	"net/http"
	"net/url"
	"strings"
	"errors"
)

func Subscribe(riviera, page string) error {
	feed, err := getFeed(page)
	if err != nil {
		return err
	}

	_, err = http.PostForm(riviera+"-/subscribe", url.Values{"url": []string{feed}})
	return err
}

func getFeed(page string) (string, error) {
	resp, err := http.Get(page)
	if err != nil {
		return "", err
	}

	contentType := resp.Header.Get("Content-Type")
	if isFeedType(contentType) {
		return page, nil
	}

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return "", err
	}

	for _, node := range doc.Find("link").Nodes {
		var rel, href, typ string
		for _, a := range node.Attr {
			switch a.Key {
			case "rel":
				rel = a.Val
			case "href":
				href = a.Val
			case "type":
				typ = a.Val
			}
		}

		if rel == "alternate" && isFeedType(typ) {
			if strings.HasPrefix(href, "/") {
				u, err := url.Parse(page)
				if err != nil {
					return "", err
				}
				u.Path = href
				return u.String(), nil
			} else {
				return href, nil
			}
		}
	}

	return "", errors.New("no feed found on page")
}

func isFeedType(contentType string) bool {
	switch contentType {
		case "application/rss+xml", "application/atom+xml", "application/xml", "text/xml":
			return true
	}
	return false
}
<commit_msg>Use regexp so Content-Type can contain parameters<commit_after>package actions

import (
	"github.com/PuerkitoBio/goquery"

	"errors"
	"net/http"
	"net/url"
	"regexp"
	"strings"
)

func Subscribe(riviera, page string) error {
	feed, err := getFeed(page)
	if err != nil {
		return err
	}

	_, err = http.PostForm(riviera+"-/subscribe", url.Values{"url": []string{feed}})
	return err
}

func getFeed(page string) (string, error) {
	resp, err := http.Get(page)
	if err != nil {
		return "", err
	}

	contentType := resp.Header.Get("Content-Type")
	if isFeedType(contentType) {
		return page, nil
	}

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return "", err
	}

	for _, node := range doc.Find("link").Nodes {
		var rel, href, typ string
		for _, a := range node.Attr {
			switch a.Key {
			case "rel":
				rel = a.Val
			case "href":
				href = a.Val
			case "type":
				typ = a.Val
			}
		}

		if rel == "alternate" && isFeedType(typ) {
			if strings.HasPrefix(href, "/") {
				u, err := url.Parse(page)
				if err != nil {
					return "", err
				}
				u.Path = href
				return u.String(), nil
			} else {
				return href, nil
			}
		}
	}

	return "", errors.New("no feed found on page")
}

var contentTypes = []*regexp.Regexp{
	regexp.MustCompile("^application/rss\\+xml"),
	regexp.MustCompile("^application/atom\\+xml"),
	regexp.MustCompile("^application/xml"),
	regexp.MustCompile("^text/xml"),
}

func isFeedType(contentType string) bool {
	for _, pat := range contentTypes {
		if pat.Match([]byte(contentType)) {
			return true
		}
	}

	return false
}
<|endoftext|>