<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sort"
	"strings"
	"text/template"
	"time"
)

var blogTitle = flag.String("title", "blog", "Blog title")
var destinationExt = flag.String("extension", "", "Destination file extension")
var sourcePath = flag.String("source", "source", "Source directory")
var destinationPath = flag.String("destination", "destination", "Destination directory")
var siteRoot = flag.String("root", "/", "Site root path")
var templatePrint = flag.String("print", "post", "Print out a template for a snippet or a blog post")
var templateAuthor = flag.String("author", "", "Set a default post author")

const templateFileName = "templates/template.html"
const rssTemplateFileName = "templates/rsstemplate.html"

func main() {

	flag.Parse()

	if *templatePrint != "" {
		var article Article
		now := time.Now().Add(15 * time.Minute)
		article.DateModified = &now

		if *templateAuthor != "" {
			article.Author = *templateAuthor
		}

		switch *templatePrint {
		case "post":
			article.Title = "Blog post"
			article.Type = Post
			break
		case "snippet":
			article.Type = Snippet
			break
		default:
			log.Fatal("post and snippet are the only allowed parameters for -print")
		}

		article.Print()

		return
	}

	log.Printf("Blog title is %s", *blogTitle)

	destinationDir, destinationDirErr := os.Open(*destinationPath)

	if destinationDirErr != nil {
		log.Fatal("Destination directory could not be open: ", destinationDirErr)
	}

	defer destinationDir.Close()

	funcMap := template.FuncMap{
		"longDate":     func(args ...interface{}) string { return args[0].(*time.Time).Format("Monday, _2 January 2006, 15:04") },
		"snippetDate":  func(args ...interface{}) string { return args[0].(*time.Time).Format("Jan _2 2006, 15:04") },
		"shortDate":    func(args ...interface{}) string { return args[0].(*time.Time).Format("Jan _2, 2006") },
		"atomDate":     func(args ...interface{}) string { return args[0].(*time.Time).Format("2006-01-02T15:04:05Z07:00") },
		"Snippet":      func(args ...interface{}) bool { return args[0].(*Article).Type == Snippet },
		"last":         func(index, count int) bool { return index == count-1 },
		"tagIndexName": func(tag string) string { return "tag-" + tag + *destinationExt },
		"path": func(article Article) string {
			return article.FullPath()
		},
	}

	mainTemplate := template.Must(template.New("template.html").Funcs(funcMap).ParseFiles(path.Join(*sourcePath, templateFileName)))
	mainRssTemplate := template.Must(template.New("rsstemplate.html").Funcs(funcMap).ParseFiles(path.Join(*sourcePath, rssTemplateFileName)))

	now := time.Now()

	postDir := path.Join(*sourcePath, "posts")

	sourceFiles, sourceFilesErr := ioutil.ReadDir(postDir)
	if sourceFilesErr != nil {
		log.Fatal("Source directory could not be read")
	}

	var articles Articles

	var indexArticles Articles
	var feedArticles Articles
	var snippetArticles Articles

	for _, sourceFileInfo := range sourceFiles {

		ext := path.Ext(sourceFileInfo.Name())

		if sourceFileInfo.IsDir() || (ext != ".markdown" && ext != ".md") {
			continue
		}

		name := strings.TrimSuffix(path.Base(sourceFileInfo.Name()), ext)

		sourceFile, _ := ioutil.ReadFile(path.Join(postDir, sourceFileInfo.Name()))

		sourceBuffer := bytes.NewBuffer(sourceFile)

		mdReader := bufio.NewReader(sourceBuffer)

		line, lineErr := mdReader.ReadString('\n')

		if lineErr != nil {
			continue
		}

		var article Article

		if strings.HasPrefix(line, "---") {
			article = ReadArticle(mdReader)
			article.Filename = name + *destinationExt
		} else {
			log.Fatal("Bad article")
			continue
		}

		if article.DateModified == nil {
			article.DateModified = new(time.Time)
			*article.DateModified = sourceFileInfo.ModTime()
		}

		article.Identifier = name

		if strings.HasSuffix(name, "draft") {
			article.Draft = true
		}

		articles = append(articles, &article)

		if article.Type == Page {
			continue
		}

		if article.Draft {
			continue
		}

		if article.Type == Post {
			feedArticles = append(feedArticles, &article)
		}

		if article.Type == Snippet {
			snippetArticles = append(snippetArticles, &article)
		}

		indexArticles = append(indexArticles, &article)
	}

	tags := map[string]bool{}

	sort.Sort(articles)
	sort.Sort(indexArticles)
	sort.Sort(feedArticles)
	sort.Sort(snippetArticles)

	indexBuffer := bytes.NewBufferString("")
	rssIndexBuffer := bytes.NewBufferString("")
	snippetrssIndexBuffer := bytes.NewBufferString("")

	mainTemplate.Execute(indexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": siteRoot, "Articles": indexArticles, "CreatedTime": now})
	mainRssTemplate.Execute(rssIndexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": siteRoot, "File": "index.xml", "Articles": feedArticles, "CreatedTime": &now})
	mainRssTemplate.Execute(snippetrssIndexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": siteRoot, "File": "snippets.xml", "Articles": snippetArticles, "CreatedTime": &now})

	for _, article := range articles {

		destFileBuffer := bytes.NewBufferString("")

		mainTemplate.Execute(destFileBuffer, map[string]interface{}{"BlogTitle": blogTitle, "Article": article, "Title": string(article.Title + " – " + *blogTitle), "Home": false, "Root": siteRoot})

		for _, tag := range article.Tags {
			tags[tag] = true
		}

		destinationFileName := path.Join(destinationDir.Name(), article.FullPath())

		os.MkdirAll(path.Join(destinationDir.Name(), article.BasePath()), os.ModePerm)

		writeErr := ioutil.WriteFile(destinationFileName, destFileBuffer.Bytes(), os.ModePerm)

		if writeErr != nil {
			log.Println(writeErr)
		}
	}

	indexFileName := path.Join(destinationDir.Name(), "index.html")
	rssIndexFileName := path.Join(destinationDir.Name(), "index.xml")
	snippetIndexFileName := path.Join(destinationDir.Name(), "snippets.xml")

	ioutil.WriteFile(indexFileName, indexBuffer.Bytes(), os.ModePerm)
	ioutil.WriteFile(rssIndexFileName, rssIndexBuffer.Bytes(), os.ModePerm)
	ioutil.WriteFile(snippetIndexFileName, snippetrssIndexBuffer.Bytes(), os.ModePerm)

	for tag := range tags {

		tagIndexBuffer := bytes.NewBufferString("")
		var tagArticles Articles

		for _, article := range indexArticles {

			if !article.HasTag(tag) {
				continue
			}

			tagArticles = append(tagArticles, article)
		}

		mainTemplate.Execute(tagIndexBuffer, map[string]interface{}{"Articles": tagArticles, "Title": "Tag: " + tag + " – " + *blogTitle, "Home": false, "Root": siteRoot})

		tagIndexFileName := path.Join(destinationDir.Name(), "tag-"+tag+*destinationExt)
		ioutil.WriteFile(tagIndexFileName, tagIndexBuffer.Bytes(), os.ModePerm)
	}
}
<commit_msg>Removed default post value for -print argument<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sort"
	"strings"
	"text/template"
	"time"
)

var blogTitle = flag.String("title", "blog", "Blog title")
var destinationExt = flag.String("extension", "", "Destination file extension")
var sourcePath = flag.String("source", "source", "Source directory")
var destinationPath = flag.String("destination", "destination", "Destination directory")
var siteRoot = flag.String("root", "/", "Site root path")
var templatePrint = flag.String("print", "", "Print out a template for a snippet or a blog post")
var templateAuthor = flag.String("author", "", "Set a default post author")

const templateFileName = "templates/template.html"
const rssTemplateFileName = "templates/rsstemplate.html"

func main() {

	flag.Parse()

	if *templatePrint != "" {
		var article Article
		now := time.Now().Add(15 * time.Minute)
		article.DateModified = &now

		if *templateAuthor != "" {
			article.Author = *templateAuthor
		}

		switch *templatePrint {
		case "post":
			article.Title = "Blog post"
			article.Type = Post
			break
		case "snippet":
			article.Type = Snippet
			break
		default:
			log.Fatal("post and snippet are the only allowed parameters for -print")
		}

		article.Print()

		return
	}

	log.Printf("Blog title is %s", *blogTitle)

	destinationDir, destinationDirErr := os.Open(*destinationPath)

	if destinationDirErr != nil {
		log.Fatal("Destination directory could not be open: ", destinationDirErr)
	}

	defer destinationDir.Close()

	funcMap := template.FuncMap{
		"longDate":     func(args ...interface{}) string { return args[0].(*time.Time).Format("Monday, _2 January 2006, 15:04") },
		"snippetDate":  func(args ...interface{}) string { return args[0].(*time.Time).Format("Jan _2 2006, 15:04") },
		"shortDate":    func(args ...interface{}) string { return args[0].(*time.Time).Format("Jan _2, 2006") },
		"atomDate":     func(args ...interface{}) string { return args[0].(*time.Time).Format("2006-01-02T15:04:05Z07:00") },
		"Snippet":      func(args ...interface{}) bool { return args[0].(*Article).Type == Snippet },
		"last":         func(index, count int) bool { return index == count-1 },
		"tagIndexName": func(tag string) string { return "tag-" + tag + *destinationExt },
		"path": func(article Article) string {
			return article.FullPath()
		},
	}

	mainTemplate := template.Must(template.New("template.html").Funcs(funcMap).ParseFiles(path.Join(*sourcePath, templateFileName)))
	mainRssTemplate := template.Must(template.New("rsstemplate.html").Funcs(funcMap).ParseFiles(path.Join(*sourcePath, rssTemplateFileName)))

	now := time.Now()

	postDir := path.Join(*sourcePath, "posts")

	sourceFiles, sourceFilesErr := ioutil.ReadDir(postDir)
	if sourceFilesErr != nil {
		log.Fatal("Source directory could not be read")
	}

	var articles Articles

	var indexArticles Articles
	var feedArticles Articles
	var snippetArticles Articles

	for _, sourceFileInfo := range sourceFiles {

		ext := path.Ext(sourceFileInfo.Name())

		if sourceFileInfo.IsDir() || (ext != ".markdown" && ext != ".md") {
			continue
		}

		name := strings.TrimSuffix(path.Base(sourceFileInfo.Name()), ext)

		sourceFile, _ := ioutil.ReadFile(path.Join(postDir, sourceFileInfo.Name()))

		sourceBuffer := bytes.NewBuffer(sourceFile)

		mdReader := bufio.NewReader(sourceBuffer)

		line, lineErr := mdReader.ReadString('\n')

		if lineErr != nil {
			continue
		}

		var article Article

		if strings.HasPrefix(line, "---") {
			article = ReadArticle(mdReader)
			article.Filename = name + *destinationExt
		} else {
			log.Fatal("Bad article")
			continue
		}

		if article.DateModified == nil {
			article.DateModified = new(time.Time)
			*article.DateModified = sourceFileInfo.ModTime()
		}

		article.Identifier = name

		if strings.HasSuffix(name, "draft") {
			article.Draft = true
		}

		articles = append(articles, &article)

		if article.Type == Page {
			continue
		}

		if article.Draft {
			continue
		}

		if article.Type == Post {
			feedArticles = append(feedArticles, &article)
		}

		if article.Type == Snippet {
			snippetArticles = append(snippetArticles, &article)
		}

		indexArticles = append(indexArticles, &article)
	}

	tags := map[string]bool{}

	sort.Sort(articles)
	sort.Sort(indexArticles)
	sort.Sort(feedArticles)
	sort.Sort(snippetArticles)

	indexBuffer := bytes.NewBufferString("")
	rssIndexBuffer := bytes.NewBufferString("")
	snippetrssIndexBuffer := bytes.NewBufferString("")

	mainTemplate.Execute(indexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": siteRoot, "Articles": indexArticles, "CreatedTime": now})
	mainRssTemplate.Execute(rssIndexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": siteRoot, "File": "index.xml", "Articles": feedArticles, "CreatedTime": &now})
	mainRssTemplate.Execute(snippetrssIndexBuffer, map[string]interface{}{"Title": blogTitle, "Home": true, "Root": siteRoot, "File": "snippets.xml", "Articles": snippetArticles, "CreatedTime": &now})

	for _, article := range articles {

		destFileBuffer := bytes.NewBufferString("")

		mainTemplate.Execute(destFileBuffer, map[string]interface{}{"BlogTitle": blogTitle, "Article": article, "Title": string(article.Title + " – " + *blogTitle), "Home": false, "Root": siteRoot})

		for _, tag := range article.Tags {
			tags[tag] = true
		}

		destinationFileName := path.Join(destinationDir.Name(), article.FullPath())

		os.MkdirAll(path.Join(destinationDir.Name(), article.BasePath()), os.ModePerm)

		writeErr := ioutil.WriteFile(destinationFileName, destFileBuffer.Bytes(), os.ModePerm)

		if writeErr != nil {
			log.Println(writeErr)
		}
	}

	indexFileName := path.Join(destinationDir.Name(), "index.html")
	rssIndexFileName := path.Join(destinationDir.Name(), "index.xml")
	snippetIndexFileName := path.Join(destinationDir.Name(), "snippets.xml")

	ioutil.WriteFile(indexFileName, indexBuffer.Bytes(), os.ModePerm)
	ioutil.WriteFile(rssIndexFileName, rssIndexBuffer.Bytes(), os.ModePerm)
	ioutil.WriteFile(snippetIndexFileName, snippetrssIndexBuffer.Bytes(), os.ModePerm)

	for tag := range tags {

		tagIndexBuffer := bytes.NewBufferString("")
		var tagArticles Articles

		for _, article := range indexArticles {

			if !article.HasTag(tag) {
				continue
			}

			tagArticles = append(tagArticles, article)
		}

		mainTemplate.Execute(tagIndexBuffer, map[string]interface{}{"Articles": tagArticles, "Title": "Tag: " + tag + " – " + *blogTitle, "Home": false, "Root": siteRoot})

		tagIndexFileName := path.Join(destinationDir.Name(), "tag-"+tag+*destinationExt)
		ioutil.WriteFile(tagIndexFileName, tagIndexBuffer.Bytes(), os.ModePerm)
	}
}
<|endoftext|>


<commit_before>// This is library for the Go language to enable use of Direct IO under
// all supported OSes of Go.
//
// Direct IO does IO to and from disk without buffering data in the OS.
// It is useful when you are reading or writing lots of data you don't
// want to fill the OS cache up with.
//
// Instead of using os.OpenFile use directio.OpenFile
//
// 	in, err := directio.OpenFile(file, os.O_RDONLY, 0666)
//
// And when reading or writing blocks, make sure you do them in chunks of
// directio.BlockSize using memory allocated by directio.AlignedBlock
//
// 	block := directio.AlignedBlock(BlockSize)
//         _, err := io.ReadFull(in, block)
package directio

import (
	"log"
	"unsafe"
)

// alignment returns alignment of the block in memory
// with reference to AlignSize
//
// Can't check alignment of a zero sized block as &block[0] is invalid
func alignment(block []byte, AlignSize int) int {
	return int(uintptr(unsafe.Pointer(&block[0])) & uintptr(AlignSize-1))
}

// AlignedBlock returns []byte of size BlockSize aligned to a multiple
// of AlignSize in memory (must be power of two)
func AlignedBlock(BlockSize int) []byte {
	block := make([]byte, BlockSize+AlignSize)
	if AlignSize == 0 {
		return block
	}
	a := alignment(block, AlignSize)
	offset := 0
	if a != 0 {
		offset = AlignSize - a
	}
	block = block[offset : offset+BlockSize]
	// Can't check alignment of a zero sized block
	if BlockSize != 0 {
		a = alignment(block, AlignSize)
		if a != 0 {
			log.Fatal("Failed to align block")
		}
	}
	return block
}
<commit_msg>Provide public function to check whether block is aligned.<commit_after>// This is library for the Go language to enable use of Direct IO under
// all supported OSes of Go.
//
// Direct IO does IO to and from disk without buffering data in the OS.
// It is useful when you are reading or writing lots of data you don't
// want to fill the OS cache up with.
//
// Instead of using os.OpenFile use directio.OpenFile
//
// 	in, err := directio.OpenFile(file, os.O_RDONLY, 0666)
//
// And when reading or writing blocks, make sure you do them in chunks of
// directio.BlockSize using memory allocated by directio.AlignedBlock
//
// 	block := directio.AlignedBlock(BlockSize)
//         _, err := io.ReadFull(in, block)
package directio

import (
	"log"
	"unsafe"
)

// alignment returns alignment of the block in memory
// with reference to AlignSize
//
// Can't check alignment of a zero sized block as &block[0] is invalid
func alignment(block []byte, AlignSize int) int {
	return int(uintptr(unsafe.Pointer(&block[0])) & uintptr(AlignSize-1))
}

// IsAligned checks wether passed byte slice is aligned
func IsAligned(block []byte) bool {
	return alignment(block, AlignSize) == 0
}

// AlignedBlock returns []byte of size BlockSize aligned to a multiple
// of AlignSize in memory (must be power of two)
func AlignedBlock(BlockSize int) []byte {
	block := make([]byte, BlockSize+AlignSize)
	if AlignSize == 0 {
		return block
	}
	a := alignment(block, AlignSize)
	offset := 0
	if a != 0 {
		offset = AlignSize - a
	}
	block = block[offset : offset+BlockSize]
	// Can't check alignment of a zero sized block
	if BlockSize != 0 {
		if !IsAligned(block) {
			log.Fatal("Failed to align block")
		}
	}
	return block
}
<|endoftext|>


<commit_before>//
//  discovery.go
//
//  Created by Martino Facchin
//  Copyright (c) 2015 Arduino LLC
//
//  Permission is hereby granted, free of charge, to any person
//  obtaining a copy of this software and associated documentation
//  files (the "Software"), to deal in the Software without
//  restriction, including without limitation the rights to use,
//  copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following
//  conditions:
//
//  The above copyright notice and this permission notice shall be
//  included in all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//  OTHER DEALINGS IN THE SOFTWARE.
//

package main

import (
	"github.com/oleksandr/bonjour"
	"log"
	"strings"
	"time"
)

const timeoutConst = 2

func GetNetworkList() ([]OsSerialPort, error) {
	resolver, err := bonjour.NewResolver(nil)
	if err != nil {
		log.Println("Failed to initialize resolver:", err.Error())
		return nil, err
	}

	timeout := make(chan bool, 1)
	go func(exitCh chan<- bool) {
		time.Sleep(timeoutConst * time.Second)
		timeout <- true
		exitCh <- true
	}(resolver.Exit)

	results := make(chan *bonjour.ServiceEntry)
	arrPorts := []OsSerialPort{}
	go func(results chan *bonjour.ServiceEntry, exitCh chan<- bool) {
		for e := range results {
			log.Printf("%s %s %d %s", e.Instance, e.AddrIPv4, e.Port, e.Text)
			var boardInfosSlice []string
			for _, element := range e.Text {
				if strings.Contains(element, "board=yun") {
					boardInfosSlice = append(boardInfosSlice, "arduino:avr:yun")
				}
			}
			arrPorts = append(arrPorts, OsSerialPort{Name: e.AddrIPv4.String(), FriendlyName: e.Instance, NetworkPort: true, RelatedNames: boardInfosSlice})
		}
	}(results, resolver.Exit)

	err = resolver.Browse("_arduino._tcp", "", results)
	if err != nil {
		log.Println("Failed to browse:", err.Error())
		return nil, err
	}
	// wait for some kind of timeout and return arrPorts
	select {
	case <-timeout:
		close(results)
		return arrPorts, nil
	}
}
<commit_msg>Save Networks instead of refreshing them completely<commit_after>//
//  discovery.go
//
//  Created by Martino Facchin
//  Copyright (c) 2015 Arduino LLC
//
//  Permission is hereby granted, free of charge, to any person
//  obtaining a copy of this software and associated documentation
//  files (the "Software"), to deal in the Software without
//  restriction, including without limitation the rights to use,
//  copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following
//  conditions:
//
//  The above copyright notice and this permission notice shall be
//  included in all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//  OTHER DEALINGS IN THE SOFTWARE.
//

package main

import (
	"github.com/oleksandr/bonjour"
	"log"
	"strings"
	"time"
)

const timeoutConst = 2

// SavedNetworkPorts contains the ports which we know are already connected
var SavedNetworkPorts []OsSerialPort

// GetNetworkList returns a list of Network Ports
// The research of network ports is articulated in two phases. First we add new ports coming from
// the bonjour module, then we prune the boards who don't respond to a ping
func GetNetworkList() ([]OsSerialPort, error) {
	newPorts, err := getPorts()
	if err != nil {
		return nil, err
	}

	tmp := SavedNetworkPorts

	for index, p1 := range tmp {
		for _, p2 := range newPorts {
			log.Printf("compare %d: %+v %+1v", index, p1, p2)
			if p1.Name == p2.Name && p2.FriendlyName == p2.FriendlyName {
				copy(SavedNetworkPorts[index:], SavedNetworkPorts[index+1:])
				SavedNetworkPorts[len(SavedNetworkPorts)-1] = OsSerialPort{}
				SavedNetworkPorts = SavedNetworkPorts[:len(SavedNetworkPorts)-1]
			}
		}
	}

	SavedNetworkPorts = append(SavedNetworkPorts, newPorts...)

	return newPorts, nil
}

func getPorts() ([]OsSerialPort, error) {
	resolver, err := bonjour.NewResolver(nil)
	if err != nil {
		log.Println("Failed to initialize resolver:", err.Error())
		return nil, err
	}

	timeout := make(chan bool, 1)
	go func(exitCh chan<- bool) {
		time.Sleep(timeoutConst * time.Second)
		timeout <- true
		exitCh <- true
	}(resolver.Exit)

	results := make(chan *bonjour.ServiceEntry)
	arrPorts := []OsSerialPort{}
	go func(results chan *bonjour.ServiceEntry, exitCh chan<- bool) {
		for e := range results {
			log.Printf("%s %s %d %s", e.Instance, e.AddrIPv4, e.Port, e.Text)
			var boardInfosSlice []string
			for _, element := range e.Text {
				if strings.Contains(element, "board=yun") {
					boardInfosSlice = append(boardInfosSlice, "arduino:avr:yun")
				}
			}
			arrPorts = append(arrPorts, OsSerialPort{Name: e.AddrIPv4.String(), FriendlyName: e.Instance, NetworkPort: true, RelatedNames: boardInfosSlice})
		}
	}(results, resolver.Exit)

	err = resolver.Browse("_arduino._tcp", "", results)
	if err != nil {
		log.Println("Failed to browse:", err.Error())
		return nil, err
	}
	// wait for some kind of timeout and return arrPorts
	select {
	case <-timeout:
		close(results)
		return arrPorts, nil
	}
}
<|endoftext|>


<commit_before>package cfutil

import (
	"errors"
	"fmt"
	consul "github.com/hashicorp/consul/api"
	"net/url"
)

func Services() (map[string]*consul.AgentService, error) {
	client, err := NewConsulClient()
	if err != nil {
		return nil, err
	}
	return client.Agent().Services()
}

func ServiceRegister(name string, path string, tags ...string) error {
	appEnv, _ := Current()
	client, err := NewConsulClient()
	if err != nil {
		return err
	}
	err = client.Agent().ServiceRegister(&consul.AgentServiceRegistration{
		Name:    name,
		Address: appEnv.ApplicationURIs[0],
		Tags:    tags,
		Check: &consul.AgentServiceCheck{
			HTTP:     fmt.Sprintf(schemaForServices() + "://" + appEnv.ApplicationURIs[0] + path),
			Interval: "30s",
		},
	})
	if err != nil {
		return err
	}
	return nil
}

func NewConsulClient() (*consul.Client, error) {
	dialString, err := consulDialstring("consul")
	if err != nil {
		return nil, err
	}
	client, consulErr := consul.NewClient(&consul.Config{
		Address: dialString,
		Scheme:  schemaForConsul(),
	})
	if consulErr != nil {
		return nil, consulErr
	}
	return client, nil
}

func consulDialstring(serviceName string) (string, error) {
	appEnv, _ := Current()
	consulService, err := appEnv.Services.WithName(serviceName)
	if err != nil {
		return "", err
	}
	port := "8500"

	uri, ok := consulService.Credentials["uri"].(string)
	if ok {
		u, err := url.Parse(uri)
		if err == nil {
			return fmt.Sprintf("%s", u.Host), nil
		}
		// Fallback to hostname/port lookup
	}

	hostname, ok := consulService.Credentials["hostname"].(string)
	if !ok {
		return "", errors.New("consul service not available")
	}
	port, ok = consulService.Credentials["port"].(string)
	if ok {
		return fmt.Sprintf("%s:%s", hostname, port), nil
	}
	return fmt.Sprintf("%s:8500", hostname), nil
}

func schemaForServices() string {
	if ForceHTTP() {
		return "http"
	}
	return "https"
}

func schemaForConsul() string {
	return "http"
}
<commit_msg>Support token via CONSUL_TOKEN env<commit_after>package cfutil

import (
	"errors"
	"fmt"
	consul "github.com/hashicorp/consul/api"
	"net/url"
	"os"
)

func Services() (map[string]*consul.AgentService, error) {
	client, err := NewConsulClient()
	if err != nil {
		return nil, err
	}
	return client.Agent().Services()
}

func ServiceRegister(name string, path string, tags ...string) error {
	appEnv, _ := Current()
	client, err := NewConsulClient()
	if err != nil {
		return err
	}
	err = client.Agent().ServiceRegister(&consul.AgentServiceRegistration{
		Name:    name,
		Address: appEnv.ApplicationURIs[0],
		Tags:    tags,
		Check: &consul.AgentServiceCheck{
			HTTP:     fmt.Sprintf(schemaForServices() + "://" + appEnv.ApplicationURIs[0] + path),
			Interval: "30s",
		},
	})
	if err != nil {
		return err
	}
	return nil
}

func NewConsulClient() (*consul.Client, error) {
	dialString, err := consulDialstring("consul")
	if err != nil {
		return nil, err
	}
	client, consulErr := consul.NewClient(&consul.Config{
		Address: dialString,
		Scheme:  schemaForConsul(),
		Token:   os.Getenv("CONSUL_TOKEN"),
	})
	if consulErr != nil {
		return nil, consulErr
	}
	return client, nil
}

func consulDialstring(serviceName string) (string, error) {
	appEnv, _ := Current()
	consulService, err := appEnv.Services.WithName(serviceName)
	if err != nil {
		return "", err
	}
	port := "8500"

	uri, ok := consulService.Credentials["uri"].(string)
	if ok {
		u, err := url.Parse(uri)
		if err == nil {
			return fmt.Sprintf("%s", u.Host), nil
		}
		// Fallback to hostname/port lookup
	}

	hostname, ok := consulService.Credentials["hostname"].(string)
	if !ok {
		return "", errors.New("consul service not available")
	}
	port, ok = consulService.Credentials["port"].(string)
	if ok {
		return fmt.Sprintf("%s:%s", hostname, port), nil
	}
	return fmt.Sprintf("%s:8500", hostname), nil
}

func schemaForServices() string {
	if ForceHTTP() {
		return "http"
	}
	return "https"
}

func schemaForConsul() string {
	return "http"
}
<|endoftext|>


<commit_before>package spdy

import (
	"net/http"
)

// SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
func SetCookie(w ResponseWriter, cookie *http.Cookie) {
	w.Header().Add("Set-Cookie", cookie.String())
}
<commit_msg>Minor addition to previous changes<commit_after><|endoftext|>


<commit_before>/*
Package quitter is a Go library to interact with GNU Social instances.

		The MIT License (MIT)

		Copyright (c) 2016 aerth

		Permission is hereby granted, free of charge, to any person obtaining a copy
		of this software and associated documentation files (the "Software"), to deal
		in the Software without restriction, including without limitation the rights
		to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
		copies of the Software, and to permit persons to whom the Software is
		furnished to do so, subject to the following conditions:

		The above copyright notice and this permission notice shall be included in all
		copies or substantial portions of the Software.
*/
package quitter

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/url"
)

var Socks string = ""

// GetPublic shows 20 new messages.
func (a Social) GetPublic() ([]Quip, error) {
	resp, err := apigun.Get(a.Scheme + a.Node + "/api/statuses/public_timeline.json")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	var quips []Quip

	var apiresponse Badrequest
	_ = json.Unmarshal(body, &apiresponse)
	if apiresponse.Error != "" {
		return nil, errors.New(apiresponse.Error)
	}

	_ = json.Unmarshal(body, &quips)

	return quips, err
}

// GetMentions shows 20 newest mentions of your username.
func (a Social) GetMentions() ([]Quip, error) {
	if a.Username == "" || a.Password == "" {
		return nil, errors.New("No user/password")
	}
	path := a.Scheme + a.Node + "/api/statuses/mentions.json"
	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}
	var quips []Quip
	_ = json.Unmarshal(body, &quips)

	return quips, err
}

// GetHome shows 20 from home timeline.
func (a Social) GetHome() ([]Quip, error) {
	if a.Username == "" || a.Password == "" {
		return nil, errors.New("No user/password")
	}

	path := "/api/statuses/home_timeline.json"

	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}
	var quips []Quip
	_ = json.Unmarshal(body, &quips)

	return quips, err

}

// DoSearch returns results for query searchstr. Does send auth info.
func (a Social) DoSearch(searchstr string) ([]Quip, error) {
	if a.Username == "" || a.Password == "" {
		return nil, errors.New("No user/password")
	}
	if searchstr == "" {
		return nil, errors.New("No query")
	}

	v := url.Values{}
	v.Set("q", searchstr)
	searchq := url.Values.Encode(v)

	path := "/api/search.json?" + searchq
	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}
	var quips []Quip
	_ = json.Unmarshal(body, &quips)

	return quips, err

}

// DoPublicSearch returns results for query searchstr. Does not send auth info.
func (a Social) DoPublicSearch(searchstr string) ([]Quip, error) {
	if searchstr == "" {
		return nil, errors.New("No query")
	}

	v := url.Values{}
	v.Set("q", searchstr)
	searchq := url.Values.Encode(v)
	resp, err := apigun.Get(a.Scheme + a.Node + "/api/search.json?" + searchq)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	var quips []Quip
	var apiresponse Badrequest
	_ = json.Unmarshal(body, &apiresponse)
	if apiresponse.Error != "" {
		return nil, errors.New(apiresponse.Error)
	}

	_ = json.Unmarshal(body, &quips)

	return quips, err

}

// DoFollow sends a request to follow a user
func (a Social) DoFollow(followstr string) (user User, err error) {
	if a.Username == "" || a.Password == "" {
		return user, errors.New("No user/password")
	}

	if followstr == "" {
		return user, errors.New("No query.")
	}

	v := url.Values{}

	v.Set("id", followstr)
	followstr = url.Values.Encode(v)

	path := "/api/friendships/create.json?" + followstr
	body, err := a.FirePOST(path, v)
	if err != nil {
		return user, err
	}

	// Return one user
	_ = json.Unmarshal(body, &user)

	return user, err

}

// DoUnfollow sends a request to unfollow a user
func (a Social) DoUnfollow(followstr string) (user User, err error) {
	if a.Username == "" || a.Password == "" {
		return user, errors.New("No user/password")
	}
	if followstr == "" {
		return user, errors.New("No query")
	}
	v := url.Values{}
	v.Set("id", followstr)
	followstr = url.Values.Encode(v)
	path := "/api/friendships/destroy.json?" + followstr
	body, err := a.FirePOST(path, v)
	if err != nil {
		return user, err
	}
	_ = json.Unmarshal(body, &user)

	return user, err

}

// GetUserTimeline returns a userlookup's timeline
func (a Social) GetUserTimeline(userlookup string) ([]Quip, error) {

	path := "/api/statuses/user_timeline.json?screen_name=" + userlookup
	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}

	var quips []Quip
	_ = json.Unmarshal(body, &quips)
	return quips, err
}

// PostNew publishes content on a.Node, returns the new quip or an error.
func (a Social) PostNew(content string) (q Quip, err error) {
	if a.Username == "" || a.Password == "" {
		return q, errors.New("No user/password")
	}

	if content == "" {
		return q, errors.New("No query")
	}
	content = url.QueryEscape(content)

	v := url.Values{}
	v.Set("status", content)
	content = url.Values.Encode(v)
	path := "/api/statuses/update.json?" + content
	body, err := a.FirePOST(path, nil)
	if err != nil {
		return q, err
	}
	_ = json.Unmarshal(body, &q)
	return q, err

}

//  ListAllGroups lists each group in a.Node
//  Some nodes don't return anything.
func (a Social) ListAllGroups() ([]Group, error) {
	if a.Username == "" || a.Password == "" {
		return nil, errors.New("No user/password")
	}

	path := a.Scheme + a.Node + "/api/statusnet/groups/list_all.json"
	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}

	var groups []Group
	err = json.Unmarshal(body, &groups)

	return groups, err
}

// ListMyGroups lists each group a a.Username is a member of
func (a Social) ListMyGroups() ([]Group, error) {
	if a.Username == "" || a.Password == "" {
		return nil, errors.New("No user/password")
	}

	path := "/api/statusnet/groups/list.json"
	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}

	var groups []Group
	_ = json.Unmarshal(body, &groups)

	return groups, err

}

// JoinGroup sends a request to join group grp.
func (a Social) JoinGroup(grp string) (g Group, err error) {
	if a.Username == "" || a.Password == "" {
		return g, errors.New("No user/password")
	}

	if grp == "" {
		return g, errors.New("Blank group detected. Not going furthur.")
	}
	v := url.Values{}

	v.Set("group_name", grp)
	v.Set("group_id", grp)
	v.Set("id", grp)
	v.Set("nickname", grp)
	grp = url.Values.Encode(v)

	path := "/api/statusnet/groups/join.json?" + grp
	body, err := a.FirePOST(path, v)
	if err != nil {
		return g, err
	}

	_ = json.Unmarshal(body, &g)

	return g, err
}

// PartGroup sends a request to part group grp.
func (a Social) PartGroup(grp string) (g Group, err error) {
	if a.Username == "" || a.Password == "" {
		return g, errors.New("No user/password")
	}

	if grp == "" {
		return g, errors.New("Blank group detected. Not going furthur.")
	}

	v := url.Values{}
	v.Set("group_name", grp)
	v.Set("group_id", grp)
	v.Set("id", grp)
	v.Set("nickname", grp)
	grp = url.Values.Encode(v)
	path := "/api/statusnet/groups/leave.json?" + grp
	body, err := a.FirePOST(path, v)
	if err != nil {
		return g, err
	}

	_ = json.Unmarshal(body, &g)

	return g, err
}
<commit_msg>fix forgotten duplicate a.Scheme + a.Node<commit_after>/*
Package quitter is a Go library to interact with GNU Social instances.

		The MIT License (MIT)

		Copyright (c) 2016 aerth

		Permission is hereby granted, free of charge, to any person obtaining a copy
		of this software and associated documentation files (the "Software"), to deal
		in the Software without restriction, including without limitation the rights
		to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
		copies of the Software, and to permit persons to whom the Software is
		furnished to do so, subject to the following conditions:

		The above copyright notice and this permission notice shall be included in all
		copies or substantial portions of the Software.
*/
package quitter

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/url"
)

var Socks string = ""

// GetPublic shows 20 new messages.
func (a Social) GetPublic() ([]Quip, error) {
	resp, err := apigun.Get(a.Scheme + a.Node + "/api/statuses/public_timeline.json")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	var quips []Quip

	var apiresponse Badrequest
	_ = json.Unmarshal(body, &apiresponse)
	if apiresponse.Error != "" {
		return nil, errors.New(apiresponse.Error)
	}

	_ = json.Unmarshal(body, &quips)

	return quips, err
}

// GetMentions shows 20 newest mentions of your username.
func (a Social) GetMentions() ([]Quip, error) {
	if a.Username == "" || a.Password == "" {
		return nil, errors.New("No user/password")
	}
	path := "/api/statuses/mentions.json"
	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}
	var quips []Quip
	_ = json.Unmarshal(body, &quips)

	return quips, err
}

// GetHome shows 20 from home timeline.
func (a Social) GetHome() ([]Quip, error) {
	if a.Username == "" || a.Password == "" {
		return nil, errors.New("No user/password")
	}

	path := "/api/statuses/home_timeline.json"

	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}
	var quips []Quip
	_ = json.Unmarshal(body, &quips)

	return quips, err

}

// DoSearch returns results for query searchstr. Does send auth info.
func (a Social) DoSearch(searchstr string) ([]Quip, error) {
	if a.Username == "" || a.Password == "" {
		return nil, errors.New("No user/password")
	}
	if searchstr == "" {
		return nil, errors.New("No query")
	}

	v := url.Values{}
	v.Set("q", searchstr)
	searchq := url.Values.Encode(v)

	path := "/api/search.json?" + searchq
	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}
	var quips []Quip
	_ = json.Unmarshal(body, &quips)

	return quips, err

}

// DoPublicSearch returns results for query searchstr. Does not send auth info.
func (a Social) DoPublicSearch(searchstr string) ([]Quip, error) {
	if searchstr == "" {
		return nil, errors.New("No query")
	}

	v := url.Values{}
	v.Set("q", searchstr)
	searchq := url.Values.Encode(v)
	resp, err := apigun.Get(a.Scheme + a.Node + "/api/search.json?" + searchq)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	var quips []Quip
	var apiresponse Badrequest
	_ = json.Unmarshal(body, &apiresponse)
	if apiresponse.Error != "" {
		return nil, errors.New(apiresponse.Error)
	}

	_ = json.Unmarshal(body, &quips)

	return quips, err

}

// DoFollow sends a request to follow a user
func (a Social) DoFollow(followstr string) (user User, err error) {
	if a.Username == "" || a.Password == "" {
		return user, errors.New("No user/password")
	}

	if followstr == "" {
		return user, errors.New("No query.")
	}

	v := url.Values{}

	v.Set("id", followstr)
	followstr = url.Values.Encode(v)

	path := "/api/friendships/create.json?" + followstr
	body, err := a.FirePOST(path, v)
	if err != nil {
		return user, err
	}

	// Return one user
	_ = json.Unmarshal(body, &user)

	return user, err

}

// DoUnfollow sends a request to unfollow a user
func (a Social) DoUnfollow(followstr string) (user User, err error) {
	if a.Username == "" || a.Password == "" {
		return user, errors.New("No user/password")
	}
	if followstr == "" {
		return user, errors.New("No query")
	}
	v := url.Values{}
	v.Set("id", followstr)
	followstr = url.Values.Encode(v)
	path := "/api/friendships/destroy.json?" + followstr
	body, err := a.FirePOST(path, v)
	if err != nil {
		return user, err
	}
	_ = json.Unmarshal(body, &user)

	return user, err

}

// GetUserTimeline returns a userlookup's timeline
func (a Social) GetUserTimeline(userlookup string) ([]Quip, error) {

	path := "/api/statuses/user_timeline.json?screen_name=" + userlookup
	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}

	var quips []Quip
	_ = json.Unmarshal(body, &quips)
	return quips, err
}

// PostNew publishes content on a.Node, returns the new quip or an error.
func (a Social) PostNew(content string) (q Quip, err error) {
	if a.Username == "" || a.Password == "" {
		return q, errors.New("No user/password")
	}

	if content == "" {
		return q, errors.New("No query")
	}
	//content = url.QueryEscape(content)

	v := url.Values{}
	v.Set("status", content)
	content = url.Values.Encode(v)
	path := "/api/statuses/update.json?" + content
	body, err := a.FirePOST(path, nil)
	if err != nil {
		return q, err
	}
	_ = json.Unmarshal(body, &q)
	return q, err

}

//  ListAllGroups lists each group in a.Node
//  Some nodes don't return anything.
func (a Social) ListAllGroups() ([]Group, error) {
	if a.Username == "" || a.Password == "" {
		return nil, errors.New("No user/password")
	}

	path := "/api/statusnet/groups/list_all.json"
	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}

	var groups []Group
	err = json.Unmarshal(body, &groups)

	return groups, err
}

// ListMyGroups lists each group a a.Username is a member of
func (a Social) ListMyGroups() ([]Group, error) {
	if a.Username == "" || a.Password == "" {
		return nil, errors.New("No user/password")
	}

	path := "/api/statusnet/groups/list.json"
	body, err := a.FireGET(path)
	if err != nil {
		return nil, err
	}

	var groups []Group
	_ = json.Unmarshal(body, &groups)

	return groups, err

}

// JoinGroup sends a request to join group grp.
func (a Social) JoinGroup(grp string) (g Group, err error) {
	if a.Username == "" || a.Password == "" {
		return g, errors.New("No user/password")
	}

	if grp == "" {
		return g, errors.New("Blank group detected. Not going furthur.")
	}
	v := url.Values{}

	v.Set("group_name", grp)
	v.Set("group_id", grp)
	v.Set("id", grp)
	v.Set("nickname", grp)
	grp = url.Values.Encode(v)

	path := "/api/statusnet/groups/join.json?" + grp
	body, err := a.FirePOST(path, v)
	if err != nil {
		return g, err
	}

	_ = json.Unmarshal(body, &g)

	return g, err
}

// PartGroup sends a request to part group grp.
func (a Social) PartGroup(grp string) (g Group, err error) {
	if a.Username == "" || a.Password == "" {
		return g, errors.New("No user/password")
	}

	if grp == "" {
		return g, errors.New("Blank group detected. Not going furthur.")
	}

	v := url.Values{}
	v.Set("group_name", grp)
	v.Set("group_id", grp)
	v.Set("id", grp)
	v.Set("nickname", grp)
	grp = url.Values.Encode(v)
	path := "/api/statusnet/groups/leave.json?" + grp
	body, err := a.FirePOST(path, v)
	if err != nil {
		return g, err
	}

	_ = json.Unmarshal(body, &g)

	return g, err
}
<|endoftext|>


<commit_before>package main

/*
#include <security/pam_appl.h>
*/
import "C"
import (
	"crypto/sha256"
	"log"
	"unsafe"

	"github.com/STNS/libnss_stns/logger"
	"github.com/STNS/libnss_stns/request"
)

// export pam_sm_authenticate
func pam_sm_authenticate(pamh *C.pam_handle_t, flags C.int, argc C.int, argv **C.char) int {
	logger.Setlog()
	c := int(argc)

	if c > 0 {
		a := GoStrings(argc, argv)
		switch a[0] {
		case "sudo":
			var passwd *C.String
			defer C.free(unsafe.Pointer(passwd))
			if len(a) > 1 {
				if C.pam_get_authtok(pamh, C.PAM_AUTHTOK, password, nil) != C.PAM_SUCCESS {
					return int(C.PAM_AUTH_ERR)
				}

				r, err := request.NewRequest(config, "sudo", "name", a[1])
				if err != nil {
					log.Println(err)
					return int(C.PAM_AUTH_ERR)
				}

				sudo, err := r.Get()
				if err != nil {
					log.Println(err)
					return int(C.PAM_AUTH_ERR)
				}

				if sha256.Sum256(C.GoString(password)) == sudo.Password {
					return int(C.PAM_AUTH_SUCCESS)
				}
			}
			return int(C.PAM_AUTH_ERR)
		default:
			return int(C.PAM_AUTH_ERR)
		}
	}
	return int(C.PAM_AUTH_ERR)
}

//export pam_sm_setcred
func pam_sm_setcred(pamh *C.pam_handle_t, flags C.int, argc C.int, argv **C.char) int {
	return int(C.PAM_SUCCESS)
}
func GoStrings(argc C.int, argv **C.char) []string {
	length := int(argc)
	tmpslice := (*[1 << 30]*C.char)(unsafe.Pointer(argv))[:length:length]
	gostrings := make([]string, length)
	for i, s := range tmpslice {
		gostrings[i] = C.GoString(s)
	}
	return gostrings
}
func main() {
}
<commit_msg>fix params count<commit_after>package main

/*
#include <security/pam_appl.h>
*/
import "C"
import (
	"crypto/sha256"
	"log"
	"unsafe"

	"github.com/STNS/libnss_stns/logger"
	"github.com/STNS/libnss_stns/request"
)

// export pam_sm_authenticate
func pam_sm_authenticate(pamh *C.pam_handle_t, flags C.int, argc C.int, argv **C.char) int {
	logger.Setlog()
	c := int(argc)

	if c > 0 {
		a := GoStrings(argc, argv)
		switch a[0] {
		case "sudo":
			var passwd *C.String
			defer C.free(unsafe.Pointer(passwd))
			if len(a) > 0 {
				if C.pam_get_authtok(pamh, C.PAM_AUTHTOK, password, nil) != C.PAM_SUCCESS {
					return int(C.PAM_AUTH_ERR)
				}

				r, err := request.NewRequest(config, "sudo", "name", a[1])
				if err != nil {
					log.Println(err)
					return int(C.PAM_AUTH_ERR)
				}

				sudo, err := r.Get()
				if err != nil {
					log.Println(err)
					return int(C.PAM_AUTH_ERR)
				}

				if sha256.Sum256(C.GoString(password)) == sudo.Password {
					return int(C.PAM_AUTH_SUCCESS)
				}
			}
			return int(C.PAM_AUTH_ERR)
		default:
			return int(C.PAM_AUTH_ERR)
		}
	}
	return int(C.PAM_AUTH_ERR)
}

//export pam_sm_setcred
func pam_sm_setcred(pamh *C.pam_handle_t, flags C.int, argc C.int, argv **C.char) int {
	return int(C.PAM_SUCCESS)
}
func GoStrings(argc C.int, argv **C.char) []string {
	length := int(argc)
	tmpslice := (*[1 << 30]*C.char)(unsafe.Pointer(argv))[:length:length]
	gostrings := make([]string, length)
	for i, s := range tmpslice {
		gostrings[i] = C.GoString(s)
	}
	return gostrings
}
func main() {
}
<|endoftext|>


<commit_before>package feedloggr2

import "encoding/xml"

type AtomFeed struct {
	XMLName xml.Name    `xml:"http://www.w3.org/2005/Atom feed"`
	Items   []*AtomItem `xml:"entry"`
}

type AtomItem struct {
	Title string      `xml:"title"`
	Links []*AtomLink `xml:"link"`
}

type AtomLink struct {
	URL string `xml:"href,attr"`
}

func parse_atom(url string, body []byte) ([]*FeedItem, error) {
	f := AtomFeed{}
	e := xml.Unmarshal(body, &f)
	if e != nil {
		return nil, e
	}

	var items []*FeedItem
	for _, i := range f.Items {
		url := i.Links[0].URL
		items = append(items, &FeedItem{
			Title: i.Title,
			URL:   url,
			Date:  Now(),
			Feed:  url,
		})
	}
	return items, nil
}
<commit_msg>Fix bug with atom feeds using the wrong url for feeds.<commit_after>package feedloggr2

import "encoding/xml"

type AtomFeed struct {
	XMLName xml.Name    `xml:"http://www.w3.org/2005/Atom feed"`
	Items   []*AtomItem `xml:"entry"`
}

type AtomItem struct {
	Title string      `xml:"title"`
	Links []*AtomLink `xml:"link"`
}

type AtomLink struct {
	URL string `xml:"href,attr"`
}

func parse_atom(url string, body []byte) ([]*FeedItem, error) {
	f := AtomFeed{}
	e := xml.Unmarshal(body, &f)
	if e != nil {
		return nil, e
	}

	var items []*FeedItem
	for _, i := range f.Items {
		item_url := i.Links[0].URL
		items = append(items, &FeedItem{
			Title: i.Title,
			URL:   item_url,
			Date:  Now(),
			Feed:  url,
		})
	}
	return items, nil
}
<|endoftext|>


<commit_before>/*
Authentication code.

Author:		Alastair Hughes
Contact:	<hobbitalastair at yandex dot com>
*/

package backend

import (
	"bytes"
	"crypto/rand"
	"fmt"
	"log"
	"net/http"

	"database/sql"
	_ "github.com/mattn/go-sqlite3"
	"golang.org/x/crypto/scrypt"
)

const passwordSize = 256

// internalError ends the request and logs an internal error.
func internalError(fail func(int), err error) {
	fail(http.StatusInternalServerError)
	log.Printf("%q\n", err)
}

// SetPassword sets the given user's password.
func SetPassword(user, password string, db *sql.DB) error {
	salt := make([]byte, passwordSize)
	err := db.QueryRow("SELECT salt FROM users WHERE name=$1", user).Scan(&salt)
	if err != nil {
		return fmt.Errorf("Failed to find existing salt: %q\n", err)
	}
	key, err := encryptPassword(password, salt)
	if err != nil {
		return fmt.Errorf("Failed to encrypt the user password: %q\n", err)
	}
	_, err = db.Exec("UPDATE users SET password=$1 WHERE name=$2", key, user)
	if err != nil {
		return fmt.Errorf("Failed to update the user password: %q\n", err)
	}
	return nil
}

// encryptPassword salts and encrypts the given password.
func encryptPassword(password string, salt []byte) ([]byte, error) {
	// We salt and encrypt the password to avoid potential security issues if
	// the db is stolen.
	// This appears to be reasonably close to "best practice", but the 1<<16
	// value probably should be checked for sanity.
	// FIXME: We don't store the 1<<16 value in the db, but it should be
	// increased as compute power grows. Doing so is complicated since some way
	// of migrating users from the old value would also need to be implemented.
	return scrypt.Key([]byte(password), salt, 1<<16, 8, 1, passwordSize)
}

// authenticateUser checks that the user and password in the given HTTP request.
func authenticateUser(writer http.ResponseWriter, fail func(int), request *http.Request, db *sql.DB) (user string, ok bool) {
	// get the user name and password.
	user, password, ok := request.BasicAuth()
	if !ok {
		writer.Header().Add("WWW-Authenticate", "basic realm=\"\"")
		fail(http.StatusUnauthorized)
		return user, false
	}

	// Retrieve the salt and database password.
	salt := make([]byte, passwordSize)
	dbpassword := []byte("")
	err := db.QueryRow("SELECT salt, password FROM users WHERE name=$1", user).Scan(&salt, &dbpassword)
	if err == sql.ErrNoRows && request.URL.Path == "/login" && request.Method == http.MethodPost {
		// FIXME: Special case creating a new user.
		log.Printf("Creating a new user %s\n", user)
		_, err = rand.Read(salt)
		if err != nil {
			internalError(fail, err)
			return user, false
		}
		key, err := encryptPassword(password, salt)
		if err != nil {
			internalError(fail, err)
			return user, false
		}
		_, err = db.Exec("INSERT INTO users VALUES ($1, $2, $3, $4)", user, salt, key, false)
		if err != nil {
			internalError(fail, err)
			return user, false
		}
		return user, true
	} else if err == sql.ErrNoRows {
		log.Printf("No such user %s\n", user)
		fail(http.StatusForbidden)
		return user, false
	} else if err != nil {
		internalError(fail, err)
		return user, false
	}

	// Check the password.
	if string(dbpassword) == "" {
		// Special case an empty password in the database.
		// This lets us create "public" demonstration accounts.
		return user, true
	}
	key, err := encryptPassword(password, salt)
	if err != nil {
		internalError(fail, err)
		return user, false
	}
	if !bytes.Equal(key, dbpassword) {
		log.Printf("Invalid password for user %s\n", user)
		fail(http.StatusForbidden)
		return user, false
	}
	return user, true
}

// authenticateRequest checks that the given user has permission to complete
// the request.
func authenticateRequest(request *http.Request, defaultResource resource) (ok bool) {
	return ((request.Method == http.MethodGet) && (defaultResource.Permissions()&get != 0)) ||
		((request.Method == http.MethodPut) && (defaultResource.Permissions()&set != 0)) ||
		((request.Method == http.MethodPost) && (defaultResource.Permissions()&create != 0)) ||
		((request.Method == http.MethodDelete) && (defaultResource.Permissions()&delete != 0))
}

// vim: sw=4 ts=4 noexpandtab
<commit_msg>Removed unused import<commit_after>/*
Authentication code.

Author:		Alastair Hughes
Contact:	<hobbitalastair at yandex dot com>
*/

package backend

import (
	"bytes"
	"crypto/rand"
	"fmt"
	"log"
	"net/http"

	"database/sql"
	"golang.org/x/crypto/scrypt"
)

const passwordSize = 256

// internalError ends the request and logs an internal error.
func internalError(fail func(int), err error) {
	fail(http.StatusInternalServerError)
	log.Printf("%q\n", err)
}

// SetPassword sets the given user's password.
func SetPassword(user, password string, db *sql.DB) error {
	salt := make([]byte, passwordSize)
	err := db.QueryRow("SELECT salt FROM users WHERE name=$1", user).Scan(&salt)
	if err != nil {
		return fmt.Errorf("Failed to find existing salt: %q\n", err)
	}
	key, err := encryptPassword(password, salt)
	if err != nil {
		return fmt.Errorf("Failed to encrypt the user password: %q\n", err)
	}
	_, err = db.Exec("UPDATE users SET password=$1 WHERE name=$2", key, user)
	if err != nil {
		return fmt.Errorf("Failed to update the user password: %q\n", err)
	}
	return nil
}

// encryptPassword salts and encrypts the given password.
func encryptPassword(password string, salt []byte) ([]byte, error) {
	// We salt and encrypt the password to avoid potential security issues if
	// the db is stolen.
	// This appears to be reasonably close to "best practice", but the 1<<16
	// value probably should be checked for sanity.
	// FIXME: We don't store the 1<<16 value in the db, but it should be
	// increased as compute power grows. Doing so is complicated since some way
	// of migrating users from the old value would also need to be implemented.
	return scrypt.Key([]byte(password), salt, 1<<16, 8, 1, passwordSize)
}

// authenticateUser checks that the user and password in the given HTTP request.
func authenticateUser(writer http.ResponseWriter, fail func(int), request *http.Request, db *sql.DB) (user string, ok bool) {
	// get the user name and password.
	user, password, ok := request.BasicAuth()
	if !ok {
		writer.Header().Add("WWW-Authenticate", "basic realm=\"\"")
		fail(http.StatusUnauthorized)
		return user, false
	}

	// Retrieve the salt and database password.
	salt := make([]byte, passwordSize)
	dbpassword := []byte("")
	err := db.QueryRow("SELECT salt, password FROM users WHERE name=$1", user).Scan(&salt, &dbpassword)
	if err == sql.ErrNoRows && request.URL.Path == "/login" && request.Method == http.MethodPost {
		// FIXME: Special case creating a new user.
		log.Printf("Creating a new user %s\n", user)
		_, err = rand.Read(salt)
		if err != nil {
			internalError(fail, err)
			return user, false
		}
		key, err := encryptPassword(password, salt)
		if err != nil {
			internalError(fail, err)
			return user, false
		}
		_, err = db.Exec("INSERT INTO users VALUES ($1, $2, $3, $4)", user, salt, key, false)
		if err != nil {
			internalError(fail, err)
			return user, false
		}
		return user, true
	} else if err == sql.ErrNoRows {
		log.Printf("No such user %s\n", user)
		fail(http.StatusForbidden)
		return user, false
	} else if err != nil {
		internalError(fail, err)
		return user, false
	}

	// Check the password.
	if string(dbpassword) == "" {
		// Special case an empty password in the database.
		// This lets us create "public" demonstration accounts.
		return user, true
	}
	key, err := encryptPassword(password, salt)
	if err != nil {
		internalError(fail, err)
		return user, false
	}
	if !bytes.Equal(key, dbpassword) {
		log.Printf("Invalid password for user %s\n", user)
		fail(http.StatusForbidden)
		return user, false
	}
	return user, true
}

// authenticateRequest checks that the given user has permission to complete
// the request.
func authenticateRequest(request *http.Request, defaultResource resource) (ok bool) {
	return ((request.Method == http.MethodGet) && (defaultResource.Permissions()&get != 0)) ||
		((request.Method == http.MethodPut) && (defaultResource.Permissions()&set != 0)) ||
		((request.Method == http.MethodPost) && (defaultResource.Permissions()&create != 0)) ||
		((request.Method == http.MethodDelete) && (defaultResource.Permissions()&delete != 0))
}

// vim: sw=4 ts=4 noexpandtab
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Shannon Wynter
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package refresh

import (
	// "net/http/httptest"
	// "bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	// "io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/fellou89/caddy-cache"
	"github.com/fellou89/caddy-cache/storage"
	"github.com/fellou89/caddy-reauth/backend"
	. "github.com/fellou89/caddy-secrets"
)

// Backend name
const Backend = "refresh"

// DefaultTimeout for sub requests
const DefaultTimeout = time.Minute

// Refresh backend provides authentication against a refresh token endpoint.
// If the refresh request returns a http 200 status code then the user
// is considered logged in.
type Refresh struct {
	refreshUrl         string
	cacheConfig        *cache.Config
	refreshCache       *cache.HTTPCache
	timeout            time.Duration
	insecureSkipVerify bool
	followRedirects    bool
	passCookies        bool
}

var SecurityContext map[string]interface{}
var accessToken string

func init() {
	SecurityContext = make(map[string]interface{})
	err := backend.Register(Backend, constructor)
	if err != nil {
		panic(err)
	}
}

func noRedirectsPolicy(req *http.Request, via []*http.Request) error {
	return errors.New("follow redirects disabled")
}

func constructor(config string) (backend.Backend, error) {
	options, err := backend.ParseOptions(config)
	if err != nil {
		return nil, err
	}

	s, found := options["url"]
	if !found {
		return nil, errors.New("url is a required parameter")
	}

	u, err := url.Parse(s)
	if err != nil {
		return nil, errors.Wrap(err, "unable to parse url "+s)
	}

	rf := &Refresh{
		refreshUrl:   u.String(),
		refreshCache: cache.NewHTTPCache(),
		cacheConfig: &cache.Config{
			Path:        "tmp",
			LockTimeout: time.Duration(5) * time.Minute,
		},
	}

	val, err := parseDurationOption(options, "timeout")
	if err != nil {
		return nil, err
	} else {
		rf.timeout = val
	}

	bval, err := parseBoolOption(options, "skipverify")
	if err != nil {
		return nil, err
	} else {
		rf.insecureSkipVerify = bval
	}

	bval, err = parseBoolOption(options, "follow")
	if err != nil {
		return nil, err
	} else {
		rf.followRedirects = bval
	}

	bval, err = parseBoolOption(options, "cookies")
	if err != nil {
		return nil, err
	} else {
		rf.passCookies = bval
	}

	// Cache config
	if s, found := options["cache_path"]; found {
		rf.cacheConfig.Path = s
	}

	val, err = parseDurationOption(options, "lock_timeout")
	if err != nil {
		return nil, err
	} else {
		rf.cacheConfig.LockTimeout = val
	}

	// Can't really define cache rules in one line, it would require refactor of parsing configs
	// so for now these two Config params stay out, and since cacheRules will be nil,
	// neither is used when creating HTTPCacheEntries
	//
	// DefaultMaxAge: time.Duration(5) * time.Minute,
	// CacheRules:    []cache.CacheRule{},
	//
	// rf.cacheConfig.DefaultMaxAge = parseDurationOption(options, "max_age")

	return rf, nil
}

func parseBoolOption(options map[string]string, key string) (bool, error) {
	if s, found := options[key]; found {
		if b, err := strconv.ParseBool(s); err != nil {
			return false, errors.Wrap(err, fmt.Sprintf("unable to parse %s %s", key, s))
		} else {
			return b, nil
		}
	}
	return false, nil
}

func parseDurationOption(options map[string]string, key string) (time.Duration, error) {
	if s, found := options[key]; found {
		if d, err := time.ParseDuration(s); err != nil {
			return time.Duration(0), errors.Wrap(err, fmt.Sprintf("unable to parse %s %s", key, s))
		} else {
			return d, nil
		}
	}
	return DefaultTimeout, nil
}

func (h Refresh) refreshRequestObject(c *http.Client, requestToAuth *http.Request) (*http.Request, error) {
	refreshToken := SecretsMap[0].Value.(string)
	data := url.Values{}
	data.Set("grant_type", "refresh_token")
	data.Add("refresh_token", refreshToken)

	refreshTokenReq, err := http.NewRequest("POST",
		"https://n0pwyybuji.execute-api.us-west-2.amazonaws.com/pre_prod/aqfer/auth/v1/access_token",
		strings.NewReader(data.Encode()))
	if err != nil {
		return nil, err
	}

	if refreshTokenReq.URL.Scheme == "https" && h.insecureSkipVerify {
		c.Transport = &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
	}

	if h.passCookies {
		for _, c := range requestToAuth.Cookies() {
			refreshTokenReq.AddCookie(c)
		}
	}

	return refreshTokenReq, nil
}

func (h *Refresh) GetAccessToken(c *http.Client, refreshTokenReq *http.Request) error {
	refreshTokenReq.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	if refreshResp, err := c.Do(refreshTokenReq); err != nil {
		return errors.Wrap(err, "Error requesting access token")

	} else {
		if refreshBody, err := ioutil.ReadAll(refreshResp.Body); err != nil {
			return errors.Wrap(err, "Error reading response body from access token refresh")

		} else {
			var b map[string]interface{}
			json.Unmarshal(refreshBody, &b)
			if b["message"] == "Forbidden" {
				return errors.New("Auth endpoint returned Forbidden")
			}
			accessToken = b["jwt_token"].(string)

			return h.newEntry(accessToken, refreshResp.StatusCode, refreshTokenReq, refreshBody)
		}
	}
}

func (h Refresh) requestSecurityContext(c *http.Client, requestToAuth *http.Request, clientJwtToken string) (interface{}, error) {
	if securityContextReq, err := http.NewRequest("GET",
		"https://n0pwyybuji.execute-api.us-west-2.amazonaws.com/pre_prod/aqfer/auth/v1/security_context?access_token="+clientJwtToken, nil); err != nil {

		return nil, err
	} else {

		securityContextReq.Header.Add("Authorization", "Bearer "+accessToken)
		if securityContextResp, err := c.Do(securityContextReq); err != nil {
			return nil, err

		} else {
			if securityContextResp.StatusCode == 400 {
				return nil, errors.New("Invalid response from security context endpoint")
			}

			if securityContextBody, err := ioutil.ReadAll(securityContextResp.Body); err != nil {
				return nil, errors.Wrap(err, "Error reading response body from security context request")

			} else {
				var b map[string]interface{}
				json.Unmarshal(securityContextBody, &b)
				if b["message"] == "Forbidden" || b["error"] != nil {
					return nil, errors.New("Auth endpoint returned Forbidden")
				}

				if err := h.newEntry(clientJwtToken, securityContextResp.StatusCode, requestToAuth, securityContextBody); err != nil {
					return nil, err
				} else {
					return b, nil
				}
			}
		}
	}
}

func (h Refresh) newEntry(key string, statusCode int, req *http.Request, body []byte) error {
	response := cache.NewResponse()
	// This creates cache files that can only live for 3 hours,
	// implementing token expiry without having to parse jwt token
	response.Header().Set("Cache-Control", "public,max-age=10800")
	response.WriteHeader(statusCode)

	// TODO: should I be using a lock?
	// lock := handler.URLLocks.Adquire(getKey(r))

	entry := cache.NewHTTPCacheEntry(key, req, response, h.cacheConfig)

	fileStore, err := storage.NewFileStorage(h.cacheConfig.Path)
	if err != nil {
		return errors.Wrap(err, "Error setting up file storage for cache")
	}
	entry.Response.SetBody(fileStore)
	entry.Response.Write(body)
	entry.Response.Close()
	h.refreshCache.Put(req, entry)
	// lock.Unlock()

	return nil
}

// Authenticate fulfils the backend interface
func (h Refresh) Authenticate(requestToAuth *http.Request) (bool, error) {
	if requestToAuth.Header.Get("Authorization") == "" {
		// No Token, Unauthorized response
		return false, nil
	}
	authHeader := strings.Split(requestToAuth.Header.Get("Authorization"), " ")
	if len(authHeader) != 2 || authHeader[0] != "Bearer" {
		return false, errors.New("Authorization token not properly formatted")
	}
	clientJwtToken := authHeader[1]

	c := &http.Client{Timeout: h.timeout}
	if !h.followRedirects {
		c.CheckRedirect = noRedirectsPolicy
	}

	// puts together refresh request to get access token
	refreshTokenReq, err := h.refreshRequestObject(c, requestToAuth)
	if err != nil {
		return false, err
	}

	if len(accessToken) == 0 { // no access token stored, request one
		if err := h.GetAccessToken(c, refreshTokenReq); err != nil {
			return false, err
		}

	} else { // access token stored; if not fresh, get new one
		if _, freshness := h.refreshCache.GetFreshness(refreshTokenReq, accessToken); freshness == 2 {
			if err := h.GetAccessToken(c, refreshTokenReq); err != nil {
				return false, err
			}
		}
	}

	// now that an access token is stored in cache, check client token freshness and get security context
	if entry, freshness := h.refreshCache.GetFreshness(requestToAuth, clientJwtToken); freshness == 0 {
		if securityContextBody, err := entry.Response.Read(); err != nil {
			return false, errors.Wrap(err, "Error reading security context from cache")

		} else {
			// security context pulled from cache and put in play
			var b interface{}
			json.Unmarshal(securityContextBody, &b)
			SecurityContext[clientJwtToken] = b
		}

	} else if freshness == 1 { // client token is not stored
		if securityContext, err := h.requestSecurityContext(c, requestToAuth, clientJwtToken); err != nil {
			if err.Error() == "Invalid response from security context endpoint" {
				// Unauthorized from security context endpoint, TODO: check with Thiru if this is correct
				return false, nil

			} else {
				return false, err
			}
		} else {
			// storing security context for first time
			SecurityContext[clientJwtToken] = securityContext
		}

	} else if freshness == 2 {
		// client token expired, Unauthorized response
		return false, nil
	}

	return true, nil
}
<commit_msg>removing map because of concurrent writes issue<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Shannon Wynter
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package refresh

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/fellou89/caddy-cache"
	"github.com/fellou89/caddy-cache/storage"
	"github.com/fellou89/caddy-reauth/backend"
	. "github.com/fellou89/caddy-secrets"
)

// Backend name
const Backend = "refresh"

// DefaultTimeout for sub requests
const DefaultTimeout = time.Minute

// Refresh backend provides authentication against a refresh token endpoint.
// If the refresh request returns a http 200 status code then the user
// is considered logged in.
type Refresh struct {
	refreshUrl         string
	cacheConfig        *cache.Config
	refreshCache       *cache.HTTPCache
	timeout            time.Duration
	insecureSkipVerify bool
	followRedirects    bool
	passCookies        bool
}

var accessToken string

func init() {
	err := backend.Register(Backend, constructor)
	if err != nil {
		panic(err)
	}
}

func noRedirectsPolicy(req *http.Request, via []*http.Request) error {
	return errors.New("follow redirects disabled")
}

func constructor(config string) (backend.Backend, error) {
	options, err := backend.ParseOptions(config)
	if err != nil {
		return nil, err
	}

	s, found := options["url"]
	if !found {
		return nil, errors.New("url is a required parameter")
	}

	u, err := url.Parse(s)
	if err != nil {
		return nil, errors.Wrap(err, "unable to parse url "+s)
	}

	rf := &Refresh{
		refreshUrl:   u.String(),
		refreshCache: cache.NewHTTPCache(),
		cacheConfig: &cache.Config{
			Path:        "tmp",
			LockTimeout: time.Duration(5) * time.Minute,
		},
	}

	val, err := parseDurationOption(options, "timeout")
	if err != nil {
		return nil, err
	} else {
		rf.timeout = val
	}

	bval, err := parseBoolOption(options, "skipverify")
	if err != nil {
		return nil, err
	} else {
		rf.insecureSkipVerify = bval
	}

	bval, err = parseBoolOption(options, "follow")
	if err != nil {
		return nil, err
	} else {
		rf.followRedirects = bval
	}

	bval, err = parseBoolOption(options, "cookies")
	if err != nil {
		return nil, err
	} else {
		rf.passCookies = bval
	}

	// Cache config
	if s, found := options["cache_path"]; found {
		rf.cacheConfig.Path = s
	}

	val, err = parseDurationOption(options, "lock_timeout")
	if err != nil {
		return nil, err
	} else {
		rf.cacheConfig.LockTimeout = val
	}

	// Can't really define cache rules in one line, it would require refactor of parsing configs
	// so for now these two Config params stay out, and since cacheRules will be nil,
	// neither is used when creating HTTPCacheEntries
	//
	// DefaultMaxAge: time.Duration(5) * time.Minute,
	// CacheRules:    []cache.CacheRule{},
	//
	// rf.cacheConfig.DefaultMaxAge = parseDurationOption(options, "max_age")

	return rf, nil
}

func parseBoolOption(options map[string]string, key string) (bool, error) {
	if s, found := options[key]; found {
		if b, err := strconv.ParseBool(s); err != nil {
			return false, errors.Wrap(err, fmt.Sprintf("unable to parse %s %s", key, s))
		} else {
			return b, nil
		}
	}
	return false, nil
}

func parseDurationOption(options map[string]string, key string) (time.Duration, error) {
	if s, found := options[key]; found {
		if d, err := time.ParseDuration(s); err != nil {
			return time.Duration(0), errors.Wrap(err, fmt.Sprintf("unable to parse %s %s", key, s))
		} else {
			return d, nil
		}
	}
	return DefaultTimeout, nil
}

func (h Refresh) refreshRequestObject(c *http.Client, requestToAuth *http.Request) (*http.Request, error) {
	refreshToken := SecretsMap[0].Value.(string)
	data := url.Values{}
	data.Set("grant_type", "refresh_token")
	data.Add("refresh_token", refreshToken)

	refreshTokenReq, err := http.NewRequest("POST", h.refreshUrl+"/aqfer/auth/v1/access_token",
		strings.NewReader(data.Encode()))
	if err != nil {
		return nil, err
	}

	if refreshTokenReq.URL.Scheme == "https" && h.insecureSkipVerify {
		c.Transport = &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
	}

	if h.passCookies {
		for _, c := range requestToAuth.Cookies() {
			refreshTokenReq.AddCookie(c)
		}
	}

	return refreshTokenReq, nil
}

func (h *Refresh) GetAccessToken(c *http.Client, refreshTokenReq *http.Request) error {
	refreshTokenReq.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	if refreshResp, err := c.Do(refreshTokenReq); err != nil {
		return errors.Wrap(err, "Error requesting access token")

	} else {
		if refreshBody, err := ioutil.ReadAll(refreshResp.Body); err != nil {
			return errors.Wrap(err, "Error reading response body from access token refresh")

		} else {
			var b map[string]interface{}
			json.Unmarshal(refreshBody, &b)
			if b["message"] == "Forbidden" {
				return errors.New("Auth endpoint returned Forbidden")
			}
			if b["jwt_token"] != nil {
				accessToken = b["jwt_token"].(string)
			}

			return h.newEntry(accessToken, refreshResp.StatusCode, refreshTokenReq, refreshBody)
		}
	}
}

func (h Refresh) requestSecurityContext(c *http.Client, requestToAuth *http.Request, clientJwtToken string) ([]byte, error) {
	if securityContextReq, err := http.NewRequest("GET",
		h.refreshUrl+"/aqfer/auth/v1/security_context?access_token="+clientJwtToken, nil); err != nil {

		return nil, err
	} else {

		securityContextReq.Header.Add("Authorization", "Bearer "+accessToken)
		if securityContextResp, err := c.Do(securityContextReq); err != nil {
			return nil, err

		} else {
			if securityContextResp.StatusCode == 400 {
				return nil, errors.New("Invalid response from security context endpoint")
			}

			if securityContextBody, err := ioutil.ReadAll(securityContextResp.Body); err != nil {
				return nil, errors.Wrap(err, "Error reading response body from security context request")

			} else {
				var b map[string]interface{}
				json.Unmarshal(securityContextBody, &b)
				if b["message"] == "Forbidden" {
					return nil, errors.New("Security Context endpoint returned Forbidden")
				}
				if b["error"] != nil {
					return nil, errors.New(fmt.Sprintf("Security Context endpoint returned error: %v", b["error"]))
				}

				if err := h.newEntry(clientJwtToken, securityContextResp.StatusCode, requestToAuth, securityContextBody); err != nil {
					return nil, err
				} else {
					return securityContextBody, nil
				}
			}
		}
	}
}

func (h Refresh) newEntry(key string, statusCode int, req *http.Request, body []byte) error {
	response := cache.NewResponse()
	// This creates cache files that can only live for 3 hours,
	// implementing token expiry without having to parse jwt token
	response.Header().Set("Cache-Control", "public,max-age=10800")
	response.WriteHeader(statusCode)

	// TODO: should I be using a lock?
	// lock := handler.URLLocks.Adquire(getKey(r))

	entry := cache.NewHTTPCacheEntry(key, req, response, h.cacheConfig)

	fileStore, err := storage.NewFileStorage(h.cacheConfig.Path)
	if err != nil {
		return errors.Wrap(err, "Error setting up file storage for cache")
	}
	entry.Response.SetBody(fileStore)
	entry.Response.Write(body)
	entry.Response.Close()
	h.refreshCache.Put(req, entry)
	// lock.Unlock()

	return nil
}

// Authenticate fulfils the backend interface
func (h Refresh) Authenticate(requestToAuth *http.Request) (bool, error) {
	if requestToAuth.Header.Get("Authorization") == "" {
		// No Token, Unauthorized response
		return false, nil
	}
	authHeader := strings.Split(requestToAuth.Header.Get("Authorization"), " ")
	if len(authHeader) != 2 || authHeader[0] != "Bearer" {
		return false, errors.New("Authorization token not properly formatted")
	}
	clientJwtToken := authHeader[1]

	c := &http.Client{Timeout: h.timeout}
	if !h.followRedirects {
		c.CheckRedirect = noRedirectsPolicy
	}

	// puts together refresh request to get access token
	refreshTokenReq, err := h.refreshRequestObject(c, requestToAuth)
	if err != nil {
		return false, err
	}

	if len(accessToken) == 0 { // no access token stored, request one
		if err := h.GetAccessToken(c, refreshTokenReq); err != nil {
			return false, err
		}

	} else { // access token stored; if not fresh, get new one
		if _, freshness := h.refreshCache.GetFreshness(refreshTokenReq, accessToken); freshness == 2 {
			if err := h.GetAccessToken(c, refreshTokenReq); err != nil {
				return false, err
			}
		}
	}

	// now that an access token is stored in cache, check client token freshness and get security context
	if entry, freshness := h.refreshCache.GetFreshness(requestToAuth, clientJwtToken); freshness == 0 {
		if securityContextBody, err := entry.Response.Read(); err != nil {
			return false, errors.Wrap(err, "Error reading security context from cache")

		} else {
			requestToAuth.ParseForm()
			requestToAuth.Form["security_context"] = []string{string(securityContextBody)}
		}

	} else if freshness == 1 { // client token is not stored
		if securityContext, err := h.requestSecurityContext(c, requestToAuth, clientJwtToken); err != nil {
			if strings.Contains(err.Error(), "Security Context endpoint returned") {
				// Unauthorized from security context endpoint, TODO: check with Thiru if this is correct
				return false, nil

			} else {
				return false, err
			}
		} else {
			requestToAuth.ParseForm()
			requestToAuth.Form["security_context"] = []string{string(securityContext)}
		}

	} else if freshness == 2 {
		// client token expired, Unauthorized response
		return false, nil
	}

	return true, nil
}
<|endoftext|>


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

// The code is the original Go implementation of rand.Prime optimized for
// generating safe (Sophie Germain) primes.
// A safe prime is a prime number of the form 2p + 1, where p is also a prime.

package paillier

import (
	"context"
	"errors"
	"fmt"
	"io"
	"math/big"
	"sync"
	"time"
)

// smallPrimes is a list of small, prime numbers that allows us to rapidly
// exclude some fraction of composite candidates when searching for a random
// prime. This list is truncated at the point where smallPrimesProduct exceeds
// a uint64. It does not include two because we ensure that the candidates are
// odd by construction.
var smallPrimes = []uint8{
	3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
}

// smallPrimesProduct is the product of the values in smallPrimes and allows us
// to reduce a candidate prime by this number and then determine whether it's
// coprime to all the elements of smallPrimes without further big.Int
// operations.
var smallPrimesProduct = new(big.Int).SetUint64(16294579238595022365)

// GenerateSafePrime tries to find a safe prime concurrently.
// The returned result is a safe prime `p` and prime `q` such that `p=2q+1`.
// Concurrency level can be controlled with the `concurrencyLevel` parameter.
// If a safe prime could not be found in the specified `timeout`, the error
// is returned. Also, if at least one search process failed, error is returned
// as well.
//
// How fast we generate a prime number is mostly a matter of luck and it depends
// on how lucky we are with drawing the first bytes.
// With today's multicore processors, we can execute the process on multiple
// cores concurrently, accept the first valid result and cancel the rest of
// work. This way, with the same finding algorithm, we can get the result
// faster.
//
// Concurrency level should be set depending on what `bitLen` of prime is
// expected. For example, as of today, on a typical workstation, for 512-bit
// safe prime, `concurrencyLevel` should be set to `1` as generating the prime
// of this length is a matter of milliseconds for a single core.
// For 1024-bit safe prime, `concurrencyLevel` should be usually set to at least
// `2` and for 2048-bit safe prime, `concurrencyLevel` must be set to at least
// `4` to get the result in a reasonable time.
//
// This function generates safe primes of at least 6 `bitLen`. For every
// generated safe prime, the two most significant bits are always set to `1`
// - we don't want the generated number to be too small.
func GenerateSafePrime(
	bitLen int,
	concurrencyLevel int,
	timeout time.Duration,
	random io.Reader,
) (p *big.Int, q *big.Int, err error) {
	if bitLen < 6 {
		return nil, nil, errors.New("safe prime size must be at least 6 bits")
	}

	primeChan := make(chan safePrime, 1)
	errChan := make(chan error, 1)

	defer close(primeChan)
	defer close(errChan)

	mutex := &sync.Mutex{}
	waitGroup := &sync.WaitGroup{}
	waitGroup.Add(concurrencyLevel)

	ctx, cancel := context.WithCancel(context.Background())

	for i := 0; i < concurrencyLevel; i++ {
		runGenPrimeRoutine(
			ctx, primeChan, errChan, mutex, waitGroup, random, bitLen,
		)
	}

	// Cancel after the specified timeout.
	go func() {
		time.Sleep(timeout)
		mutex.Lock()
		cancel()
		mutex.Unlock()
	}()

	select {
	case result := <-primeChan:
		mutex.Lock()
		cancel()
		mutex.Unlock()
		p, q, err = result.p, result.q, nil
	case err := <-errChan:
		mutex.Lock()
		cancel()
		mutex.Unlock()
		p, q, err = nil, nil, err
	case <-ctx.Done():
		p, q, err = nil, nil, fmt.Errorf("generator timed out after %v", timeout)
	}

	waitGroup.Wait()
	return
}

type safePrime struct {
	p *big.Int // p = 2q + 1
	q *big.Int
}

// Starts a Goroutine searching for a safe prime of the specified `pBitLen`.
// If succeeds, writes prime `p` and prime `q` such that `p = 2q+1` to the
// `primeChan`. Prime `p` has a bit length equal to `pBitLen` and prime `q` has
// a bit length equal to `pBitLen-1`.
//
// The algorithm is as follows:
// 1. Generate a random odd number `q` of length `pBitLen-1` with two the most
//    significant bits set to `1`.
// 2. Execute preliminary primality test on `q` checking whether it is coprime
//    to all the elements of `smallPrimes`. It allows to eliminate trivial
//    cases quickly, when `q` is obviously no prime, without running an
//    expensive final primality tests.
//    If `q` is coprime to all of the `smallPrimes`, then go to the point 3.
//    If not, add `2` and try again. Do it at most 10 times.
// 3. Check the potentially prime `q`, whether `q = 1 (mod 3)`. This will
//    happen for 50% of cases.
//    If it is, then `p = 2q+1` will be a multiple of 3, so it will be obviously
//    not a prime number. In this case, add `2` and try again. Do it at most 10
//    times. If `q != 1 (mod 3)`, go to the point 4.
// 4. Now we know `q` is potentially prime and `p = 2q+1` is not a multiple of
//    3. We execute a preliminary primality test on `p`, checking whether
//    it is coprime to all the elements of `smallPrimes` just like we did for
//    `q` in point 2. If `p` is not coprime to at least one element of the
//    `smallPrimes`, then go back to point 1.
//    If `p` is coprime to all the elements of `smallPrimes`, go to point 5.
// 5. At this point, we know `q` is potentially prime, and `p=q+1` is also
//    potentially prime. We need to execute a final primality test for `q`.
//    We apply Miller-Rabin and Baillie-PSW tests. If they succeed, it means
//    that `q` is prime with a very high probability. Knowing `q` is prime,
//    we use Pocklington's criterion to prove the primality of `p=2q+1`, that
//    is, we execute Fermat primality test to base 2 checking whether
//    `2^{p-1} = 1 (mod p)`. It's significantly faster than running full
//    Miller-Rabin and Baillie-PSW for `p`.
//    If `q` and `p` are found to be prime, return them as a result. If not, go
//    back to the point 1.
func runGenPrimeRoutine(
	ctx context.Context,
	primeChan chan safePrime,
	errChan chan error,
	mutex *sync.Mutex,
	waitGroup *sync.WaitGroup,
	rand io.Reader,
	pBitLen int,
) {
	qBitLen := pBitLen - 1
	b := uint(qBitLen % 8)
	if b == 0 {
		b = 8
	}

	bytes := make([]byte, (qBitLen+7)/8)
	p := new(big.Int)
	q := new(big.Int)

	bigMod := new(big.Int)

	go func() {
		for {
			select {
			case <-ctx.Done():
				waitGroup.Done()
				return
			default:
				_, err := io.ReadFull(rand, bytes)
				if err != nil {
					errChan <- err
					return
				}

				// Clear bits in the first byte to make sure the candidate has
				// a size <= bits.
				bytes[0] &= uint8(int(1<<b) - 1)
				// Don't let the value be too small, i.e, set the most
				// significant two bits.
				// Setting the top two bits, rather than just the top bit,
				// means that when two of these values are multiplied together,
				// the result isn't ever one bit short.
				if b >= 2 {
					bytes[0] |= 3 << (b - 2)
				} else {
					// Here b==1, because b cannot be zero.
					bytes[0] |= 1
					if len(bytes) > 1 {
						bytes[1] |= 0x80
					}
				}
				// Make the value odd since an even number this large certainly
				// isn't prime.
				bytes[len(bytes)-1] |= 1

				q.SetBytes(bytes)

				// Calculate the value mod the product of smallPrimes. If it's
				// a multiple of any of these primes we add two until it isn't.
				// The probability of overflowing is minimal and can be ignored
				// because we still perform Miller-Rabin tests on the result.
				bigMod.Mod(q, smallPrimesProduct)
				mod := bigMod.Uint64()

			NextDelta:
				for delta := uint64(0); delta < 1<<20; delta += 2 {
					m := mod + delta
					for _, prime := range smallPrimes {
						if m%uint64(prime) == 0 && (qBitLen > 6 || m != uint64(prime)) {
							continue NextDelta
						}
					}

					if delta > 0 {
						bigMod.SetUint64(delta)
						q.Add(q, bigMod)
					}

					// If `q = 1 (mod 3)`, then `p` is a multiple of `3` so it's
					// obviously no prime and such `q` should be rejected.
					// This will happen in 50% of cases and we should detect
					// and eliminate them early.
					//
					// Explanation:
					// If q = 1 (mod 3) then there exists a q' such that:
					// q = 3q' + 1
					//
					// Since p = 2q + 1:
					// p = 2q + 1 = 2(3q' + 1) + 1 = 6q' + 2 + 1 = 6q' + 3 =
					//   = 3(2q' + 1)
					// So `p` is a multiple of `3`.
					qMod3 := new(big.Int).Mod(q, big.NewInt(3))
					if qMod3.Cmp(big.NewInt(1)) == 0 {
						continue NextDelta
					}

					// p = 2q+1
					p.Mul(q, big.NewInt(2))
					p.Add(p, big.NewInt(1))
					if !isPrimeCandidate(p) {
						continue NextDelta
					}

					break
				}

				// There is a tiny possibility that, by adding delta, we caused
				// the number to be one bit too long. Thus we check BitLen
				// here.
				if q.ProbablyPrime(20) &&
					isPocklingtonCriterionSatisfied(p) &&
					q.BitLen() == qBitLen {

					mutex.Lock()
					if ctx.Err() == nil {
						primeChan <- safePrime{p, q}
					}
					mutex.Unlock()

					waitGroup.Done()
					return
				}
			}
		}
	}()
}

func isPocklingtonCriterionSatisfied(p *big.Int) bool {
	return new(big.Int).Exp(
		big.NewInt(2),
		new(big.Int).Sub(p, big.NewInt(1)),
		p,
	).Cmp(big.NewInt(1)) == 0
}

func isPrimeCandidate(number *big.Int) bool {
	m := new(big.Int).Mod(number, smallPrimesProduct).Uint64()

	for _, prime := range smallPrimes {
		if m%uint64(prime) == 0 && m != uint64(prime) {
			return false
		}
	}

	return true
}
<commit_msg>Deadlock fixed - result channel buffer increased<commit_after>// Copyright 2011 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.

// The code is the original Go implementation of rand.Prime optimized for
// generating safe (Sophie Germain) primes.
// A safe prime is a prime number of the form 2p + 1, where p is also a prime.

package paillier

import (
	"context"
	"errors"
	"fmt"
	"io"
	"math/big"
	"sync"
	"time"
)

// smallPrimes is a list of small, prime numbers that allows us to rapidly
// exclude some fraction of composite candidates when searching for a random
// prime. This list is truncated at the point where smallPrimesProduct exceeds
// a uint64. It does not include two because we ensure that the candidates are
// odd by construction.
var smallPrimes = []uint8{
	3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
}

// smallPrimesProduct is the product of the values in smallPrimes and allows us
// to reduce a candidate prime by this number and then determine whether it's
// coprime to all the elements of smallPrimes without further big.Int
// operations.
var smallPrimesProduct = new(big.Int).SetUint64(16294579238595022365)

// GenerateSafePrime tries to find a safe prime concurrently.
// The returned result is a safe prime `p` and prime `q` such that `p=2q+1`.
// Concurrency level can be controlled with the `concurrencyLevel` parameter.
// If a safe prime could not be found in the specified `timeout`, the error
// is returned. Also, if at least one search process failed, error is returned
// as well.
//
// How fast we generate a prime number is mostly a matter of luck and it depends
// on how lucky we are with drawing the first bytes.
// With today's multicore processors, we can execute the process on multiple
// cores concurrently, accept the first valid result and cancel the rest of
// work. This way, with the same finding algorithm, we can get the result
// faster.
//
// Concurrency level should be set depending on what `bitLen` of prime is
// expected. For example, as of today, on a typical workstation, for 512-bit
// safe prime, `concurrencyLevel` should be set to `1` as generating the prime
// of this length is a matter of milliseconds for a single core.
// For 1024-bit safe prime, `concurrencyLevel` should be usually set to at least
// `2` and for 2048-bit safe prime, `concurrencyLevel` must be set to at least
// `4` to get the result in a reasonable time.
//
// This function generates safe primes of at least 6 `bitLen`. For every
// generated safe prime, the two most significant bits are always set to `1`
// - we don't want the generated number to be too small.
func GenerateSafePrime(
	bitLen int,
	concurrencyLevel int,
	timeout time.Duration,
	random io.Reader,
) (p *big.Int, q *big.Int, err error) {
	if bitLen < 6 {
		return nil, nil, errors.New("safe prime size must be at least 6 bits")
	}

	primeChan := make(chan safePrime, concurrencyLevel)
	errChan := make(chan error, concurrencyLevel)

	defer close(primeChan)
	defer close(errChan)

	mutex := &sync.Mutex{}
	waitGroup := &sync.WaitGroup{}

	ctx, cancel := context.WithCancel(context.Background())

	for i := 0; i < concurrencyLevel; i++ {
		waitGroup.Add(1)
		runGenPrimeRoutine(
			ctx, primeChan, errChan, mutex, waitGroup, random, bitLen,
		)
	}

	// Cancel after the specified timeout.
	go func() {
		time.Sleep(timeout)
		mutex.Lock()
		cancel()
		mutex.Unlock()
	}()

	select {
	case result := <-primeChan:
		mutex.Lock()
		cancel()
		mutex.Unlock()
		p, q, err = result.p, result.q, nil
	case err := <-errChan:
		mutex.Lock()
		cancel()
		mutex.Unlock()
		p, q, err = nil, nil, err
	case <-ctx.Done():
		p, q, err = nil, nil, fmt.Errorf("generator timed out after %v", timeout)
	}

	waitGroup.Wait()
	return
}

type safePrime struct {
	p *big.Int // p = 2q + 1
	q *big.Int
}

// Starts a Goroutine searching for a safe prime of the specified `pBitLen`.
// If succeeds, writes prime `p` and prime `q` such that `p = 2q+1` to the
// `primeChan`. Prime `p` has a bit length equal to `pBitLen` and prime `q` has
// a bit length equal to `pBitLen-1`.
//
// The algorithm is as follows:
// 1. Generate a random odd number `q` of length `pBitLen-1` with two the most
//    significant bits set to `1`.
// 2. Execute preliminary primality test on `q` checking whether it is coprime
//    to all the elements of `smallPrimes`. It allows to eliminate trivial
//    cases quickly, when `q` is obviously no prime, without running an
//    expensive final primality tests.
//    If `q` is coprime to all of the `smallPrimes`, then go to the point 3.
//    If not, add `2` and try again. Do it at most 10 times.
// 3. Check the potentially prime `q`, whether `q = 1 (mod 3)`. This will
//    happen for 50% of cases.
//    If it is, then `p = 2q+1` will be a multiple of 3, so it will be obviously
//    not a prime number. In this case, add `2` and try again. Do it at most 10
//    times. If `q != 1 (mod 3)`, go to the point 4.
// 4. Now we know `q` is potentially prime and `p = 2q+1` is not a multiple of
//    3. We execute a preliminary primality test on `p`, checking whether
//    it is coprime to all the elements of `smallPrimes` just like we did for
//    `q` in point 2. If `p` is not coprime to at least one element of the
//    `smallPrimes`, then go back to point 1.
//    If `p` is coprime to all the elements of `smallPrimes`, go to point 5.
// 5. At this point, we know `q` is potentially prime, and `p=q+1` is also
//    potentially prime. We need to execute a final primality test for `q`.
//    We apply Miller-Rabin and Baillie-PSW tests. If they succeed, it means
//    that `q` is prime with a very high probability. Knowing `q` is prime,
//    we use Pocklington's criterion to prove the primality of `p=2q+1`, that
//    is, we execute Fermat primality test to base 2 checking whether
//    `2^{p-1} = 1 (mod p)`. It's significantly faster than running full
//    Miller-Rabin and Baillie-PSW for `p`.
//    If `q` and `p` are found to be prime, return them as a result. If not, go
//    back to the point 1.
func runGenPrimeRoutine(
	ctx context.Context,
	primeChan chan safePrime,
	errChan chan error,
	mutex *sync.Mutex,
	waitGroup *sync.WaitGroup,
	rand io.Reader,
	pBitLen int,
) {
	qBitLen := pBitLen - 1
	b := uint(qBitLen % 8)
	if b == 0 {
		b = 8
	}

	bytes := make([]byte, (qBitLen+7)/8)
	p := new(big.Int)
	q := new(big.Int)

	bigMod := new(big.Int)

	go func() {
		for {
			select {
			case <-ctx.Done():
				waitGroup.Done()
				return
			default:
				_, err := io.ReadFull(rand, bytes)
				if err != nil {
					errChan <- err
					return
				}

				// Clear bits in the first byte to make sure the candidate has
				// a size <= bits.
				bytes[0] &= uint8(int(1<<b) - 1)
				// Don't let the value be too small, i.e, set the most
				// significant two bits.
				// Setting the top two bits, rather than just the top bit,
				// means that when two of these values are multiplied together,
				// the result isn't ever one bit short.
				if b >= 2 {
					bytes[0] |= 3 << (b - 2)
				} else {
					// Here b==1, because b cannot be zero.
					bytes[0] |= 1
					if len(bytes) > 1 {
						bytes[1] |= 0x80
					}
				}
				// Make the value odd since an even number this large certainly
				// isn't prime.
				bytes[len(bytes)-1] |= 1

				q.SetBytes(bytes)

				// Calculate the value mod the product of smallPrimes. If it's
				// a multiple of any of these primes we add two until it isn't.
				// The probability of overflowing is minimal and can be ignored
				// because we still perform Miller-Rabin tests on the result.
				bigMod.Mod(q, smallPrimesProduct)
				mod := bigMod.Uint64()

			NextDelta:
				for delta := uint64(0); delta < 1<<20; delta += 2 {
					m := mod + delta
					for _, prime := range smallPrimes {
						if m%uint64(prime) == 0 && (qBitLen > 6 || m != uint64(prime)) {
							continue NextDelta
						}
					}

					if delta > 0 {
						bigMod.SetUint64(delta)
						q.Add(q, bigMod)
					}

					// If `q = 1 (mod 3)`, then `p` is a multiple of `3` so it's
					// obviously no prime and such `q` should be rejected.
					// This will happen in 50% of cases and we should detect
					// and eliminate them early.
					//
					// Explanation:
					// If q = 1 (mod 3) then there exists a q' such that:
					// q = 3q' + 1
					//
					// Since p = 2q + 1:
					// p = 2q + 1 = 2(3q' + 1) + 1 = 6q' + 2 + 1 = 6q' + 3 =
					//   = 3(2q' + 1)
					// So `p` is a multiple of `3`.
					qMod3 := new(big.Int).Mod(q, big.NewInt(3))
					if qMod3.Cmp(big.NewInt(1)) == 0 {
						continue NextDelta
					}

					// p = 2q+1
					p.Mul(q, big.NewInt(2))
					p.Add(p, big.NewInt(1))
					if !isPrimeCandidate(p) {
						continue NextDelta
					}

					break
				}

				// There is a tiny possibility that, by adding delta, we caused
				// the number to be one bit too long. Thus we check BitLen
				// here.
				if q.ProbablyPrime(20) &&
					isPocklingtonCriterionSatisfied(p) &&
					q.BitLen() == qBitLen {

					mutex.Lock()
					if ctx.Err() == nil {
						primeChan <- safePrime{p, q}
					}
					mutex.Unlock()

					waitGroup.Done()
					return
				}
			}
		}
	}()
}

func isPocklingtonCriterionSatisfied(p *big.Int) bool {
	return new(big.Int).Exp(
		big.NewInt(2),
		new(big.Int).Sub(p, big.NewInt(1)),
		p,
	).Cmp(big.NewInt(1)) == 0
}

func isPrimeCandidate(number *big.Int) bool {
	m := new(big.Int).Mod(number, smallPrimesProduct).Uint64()

	for _, prime := range smallPrimes {
		if m%uint64(prime) == 0 && m != uint64(prime) {
			return false
		}
	}

	return true
}
<|endoftext|>