Several fixes including vendoring ed25519 code under torutil
This commit is contained in:
parent
db2d028c4a
commit
4d7c47a3d4
|
@ -3,7 +3,7 @@ package control
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/util"
|
||||
"github.com/cretz/bine/torutil"
|
||||
)
|
||||
|
||||
// SetConf invokes SETCONF.
|
||||
|
@ -20,7 +20,7 @@ func (c *Conn) sendSetConf(cmd string, entries []*KeyVal) error {
|
|||
for _, entry := range entries {
|
||||
cmd += " " + entry.Key
|
||||
if entry.ValSet() {
|
||||
cmd += "=" + util.EscapeSimpleQuotedStringIfNeeded(entry.Val)
|
||||
cmd += "=" + torutil.EscapeSimpleQuotedStringIfNeeded(entry.Val)
|
||||
}
|
||||
}
|
||||
return c.sendRequestIgnoreResponse(cmd)
|
||||
|
@ -35,10 +35,10 @@ func (c *Conn) GetConf(keys ...string) ([]*KeyVal, error) {
|
|||
data := resp.DataWithReply()
|
||||
ret := make([]*KeyVal, 0, len(data))
|
||||
for _, data := range data {
|
||||
key, val, ok := util.PartitionString(data, '=')
|
||||
key, val, ok := torutil.PartitionString(data, '=')
|
||||
entry := &KeyVal{Key: key}
|
||||
if ok {
|
||||
if entry.Val, err = util.UnescapeSimpleQuotedStringIfNeeded(val); err != nil {
|
||||
if entry.Val, err = torutil.UnescapeSimpleQuotedStringIfNeeded(val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(entry.Val) == 0 {
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cretz/bine/util"
|
||||
"github.com/cretz/bine/torutil"
|
||||
)
|
||||
|
||||
// EventCode represents an asynchronous event code (ref control spec 4.1).
|
||||
|
@ -120,6 +120,7 @@ func (c *Conn) EventWait(
|
|||
ctx context.Context, events []EventCode, predicate func(Event) (bool, error),
|
||||
) (Event, error) {
|
||||
eventCh := make(chan Event, 10)
|
||||
defer close(eventCh)
|
||||
if err := c.AddEventListener(eventCh, events...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -212,7 +213,7 @@ func (c *Conn) AddEventListener(ch chan<- Event, events ...EventCode) error {
|
|||
// no longer be listened to. If no events are provided, this is essentially a
|
||||
// no-op.
|
||||
func (c *Conn) RemoveEventListener(ch chan<- Event, events ...EventCode) error {
|
||||
|
||||
c.removeEventListenerFromMap(ch, events...)
|
||||
return c.sendSetEvents()
|
||||
}
|
||||
|
||||
|
@ -280,7 +281,7 @@ func (c *Conn) relayAsyncEvents(resp *Response) {
|
|||
code, dataArray = resp.Data[0], resp.Data[1:]
|
||||
} else {
|
||||
// Otherwise, the reply line has the data
|
||||
code, data, _ = util.PartitionString(resp.Reply, ' ')
|
||||
code, data, _ = torutil.PartitionString(resp.Reply, ' ')
|
||||
}
|
||||
// Only relay if there are chans
|
||||
eventCode := EventCode(code)
|
||||
|
@ -413,14 +414,14 @@ type CircuitEvent struct {
|
|||
// ParseCircuitEvent parses the event.
|
||||
func ParseCircuitEvent(raw string) *CircuitEvent {
|
||||
event := &CircuitEvent{Raw: raw}
|
||||
event.CircuitID, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.CircuitID, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
var ok bool
|
||||
event.Status, raw, ok = util.PartitionString(raw, ' ')
|
||||
event.Status, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
var attr string
|
||||
first := true
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "BUILD_FLAGS":
|
||||
event.BuildFlags = strings.Split(val, ",")
|
||||
|
@ -472,19 +473,19 @@ type StreamEvent struct {
|
|||
// ParseStreamEvent parses the event.
|
||||
func ParseStreamEvent(raw string) *StreamEvent {
|
||||
event := &StreamEvent{Raw: raw}
|
||||
event.StreamID, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Status, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.CircuitID, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.StreamID, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.Status, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.CircuitID, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
var ok bool
|
||||
event.TargetAddress, raw, ok = util.PartitionString(raw, ' ')
|
||||
if target, port, hasPort := util.PartitionStringFromEnd(event.TargetAddress, ':'); hasPort {
|
||||
event.TargetAddress, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
if target, port, hasPort := torutil.PartitionStringFromEnd(event.TargetAddress, ':'); hasPort {
|
||||
event.TargetAddress = target
|
||||
event.TargetPort, _ = strconv.Atoi(port)
|
||||
}
|
||||
var attr string
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "REASON":
|
||||
event.Reason = val
|
||||
|
@ -494,7 +495,7 @@ func ParseStreamEvent(raw string) *StreamEvent {
|
|||
event.Source = val
|
||||
case "SOURCE_ADDR":
|
||||
event.SourceAddress = val
|
||||
if source, port, hasPort := util.PartitionStringFromEnd(event.SourceAddress, ':'); hasPort {
|
||||
if source, port, hasPort := torutil.PartitionStringFromEnd(event.SourceAddress, ':'); hasPort {
|
||||
event.SourceAddress = source
|
||||
event.SourcePort, _ = strconv.Atoi(port)
|
||||
}
|
||||
|
@ -521,13 +522,13 @@ type ORConnEvent struct {
|
|||
// ParseORConnEvent parses the event.
|
||||
func ParseORConnEvent(raw string) *ORConnEvent {
|
||||
event := &ORConnEvent{Raw: raw}
|
||||
event.Target, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Target, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
var ok bool
|
||||
event.Status, raw, ok = util.PartitionString(raw, ' ')
|
||||
event.Status, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
var attr string
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "REASON":
|
||||
event.Reason = val
|
||||
|
@ -554,9 +555,9 @@ type BandwidthEvent struct {
|
|||
func ParseBandwidthEvent(raw string) *BandwidthEvent {
|
||||
event := &BandwidthEvent{Raw: raw}
|
||||
var temp string
|
||||
temp, raw, _ = util.PartitionString(raw, ' ')
|
||||
temp, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.BytesRead, _ = strconv.ParseInt(temp, 10, 64)
|
||||
temp, raw, _ = util.PartitionString(raw, ' ')
|
||||
temp, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.BytesWritten, _ = strconv.ParseInt(temp, 10, 64)
|
||||
return event
|
||||
}
|
||||
|
@ -607,23 +608,23 @@ type AddrMapEvent struct {
|
|||
// ParseAddrMapEvent parses the event.
|
||||
func ParseAddrMapEvent(raw string) *AddrMapEvent {
|
||||
event := &AddrMapEvent{Raw: raw}
|
||||
event.Address, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.NewAddress, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Address, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.NewAddress, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
var ok bool
|
||||
// Skip local expiration, use UTC one later
|
||||
_, raw, ok = util.PartitionString(raw, ' ')
|
||||
_, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
var attr string
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "error":
|
||||
event.ErrorCode = val
|
||||
case "EXPIRES":
|
||||
val, _ = util.UnescapeSimpleQuotedString(val)
|
||||
val, _ = torutil.UnescapeSimpleQuotedString(val)
|
||||
event.Expires = parseISOTime(val)
|
||||
case "CACHED":
|
||||
event.Cached, _ = util.UnescapeSimpleQuotedStringIfNeeded(val)
|
||||
event.Cached, _ = torutil.UnescapeSimpleQuotedStringIfNeeded(val)
|
||||
}
|
||||
}
|
||||
return event
|
||||
|
@ -657,14 +658,14 @@ type StatusEvent struct {
|
|||
// ParseStatusEvent parses the event.
|
||||
func ParseStatusEvent(typ EventCode, raw string) *StatusEvent {
|
||||
event := &StatusEvent{Raw: raw, Type: typ, Arguments: map[string]string{}}
|
||||
event.Severity, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Severity, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
var ok bool
|
||||
event.Action, raw, ok = util.PartitionString(raw, ' ')
|
||||
event.Action, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
var attr string
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
event.Arguments[key], _ = util.UnescapeSimpleQuotedStringIfNeeded(val)
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
event.Arguments[key], _ = torutil.UnescapeSimpleQuotedStringIfNeeded(val)
|
||||
}
|
||||
return event
|
||||
}
|
||||
|
@ -683,9 +684,9 @@ type GuardEvent struct {
|
|||
// ParseGuardEvent parses the event.
|
||||
func ParseGuardEvent(raw string) *GuardEvent {
|
||||
event := &GuardEvent{Raw: raw}
|
||||
event.Type, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Name, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Status, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Type, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.Name, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.Status, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
return event
|
||||
}
|
||||
|
||||
|
@ -717,12 +718,12 @@ type StreamBandwidthEvent struct {
|
|||
func ParseStreamBandwidthEvent(raw string) *StreamBandwidthEvent {
|
||||
event := &StreamBandwidthEvent{Raw: raw}
|
||||
var temp string
|
||||
temp, raw, _ = util.PartitionString(raw, ' ')
|
||||
temp, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.BytesRead, _ = strconv.ParseInt(temp, 10, 64)
|
||||
temp, raw, _ = util.PartitionString(raw, ' ')
|
||||
temp, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.BytesWritten, _ = strconv.ParseInt(temp, 10, 64)
|
||||
temp, raw, _ = util.PartitionString(raw, ' ')
|
||||
temp, _ = util.UnescapeSimpleQuotedString(temp)
|
||||
temp, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
temp, _ = torutil.UnescapeSimpleQuotedString(temp)
|
||||
event.Time = parseISOTime2Frac(temp)
|
||||
return event
|
||||
}
|
||||
|
@ -743,21 +744,21 @@ func ParseClientsSeenEvent(raw string) *ClientsSeenEvent {
|
|||
event := &ClientsSeenEvent{Raw: raw}
|
||||
var temp string
|
||||
var ok bool
|
||||
temp, raw, ok = util.PartitionString(raw, ' ')
|
||||
temp, _ = util.UnescapeSimpleQuotedString(temp)
|
||||
temp, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
temp, _ = torutil.UnescapeSimpleQuotedString(temp)
|
||||
event.TimeStarted = parseISOTime(temp)
|
||||
strToMap := func(str string) map[string]int {
|
||||
ret := map[string]int{}
|
||||
for _, keyVal := range strings.Split(str, ",") {
|
||||
key, val, _ := util.PartitionString(keyVal, '=')
|
||||
key, val, _ := torutil.PartitionString(keyVal, '=')
|
||||
ret[key], _ = strconv.Atoi(val)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
var attr string
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "CountrySummary":
|
||||
event.CountrySummary = strToMap(val)
|
||||
|
@ -802,16 +803,16 @@ type BuildTimeoutSetEvent struct {
|
|||
func ParseBuildTimeoutSetEvent(raw string) *BuildTimeoutSetEvent {
|
||||
event := &BuildTimeoutSetEvent{Raw: raw}
|
||||
var ok bool
|
||||
event.Type, raw, ok = util.PartitionString(raw, ' ')
|
||||
_, raw, ok = util.PartitionString(raw, ' ')
|
||||
event.Type, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
_, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
var attr string
|
||||
parseFloat := func(val string) float32 {
|
||||
f, _ := strconv.ParseFloat(val, 32)
|
||||
return float32(f)
|
||||
}
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "TOTAL_TIMES":
|
||||
event.TotalTimes, _ = strconv.Atoi(val)
|
||||
|
@ -886,14 +887,14 @@ type CircuitMinorEvent struct {
|
|||
// ParseCircuitMinorEvent parses the event.
|
||||
func ParseCircuitMinorEvent(raw string) *CircuitMinorEvent {
|
||||
event := &CircuitMinorEvent{Raw: raw}
|
||||
event.CircuitID, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.CircuitID, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
var ok bool
|
||||
event.Event, raw, ok = util.PartitionString(raw, ' ')
|
||||
event.Event, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
var attr string
|
||||
first := true
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "BUILD_FLAGS":
|
||||
event.BuildFlags = strings.Split(val, ",")
|
||||
|
@ -934,11 +935,11 @@ type TransportLaunchedEvent struct {
|
|||
// ParseTransportLaunchedEvent parses the event.
|
||||
func ParseTransportLaunchedEvent(raw string) *TransportLaunchedEvent {
|
||||
event := &TransportLaunchedEvent{Raw: raw}
|
||||
event.Type, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Name, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Address, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Type, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.Name, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.Address, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
var temp string
|
||||
temp, raw, _ = util.PartitionString(raw, ' ')
|
||||
temp, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.Port, _ = strconv.Atoi(temp)
|
||||
return event
|
||||
}
|
||||
|
@ -961,8 +962,8 @@ func ParseConnBandwidthEvent(raw string) *ConnBandwidthEvent {
|
|||
ok := true
|
||||
var attr string
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "ID":
|
||||
event.ConnID = val
|
||||
|
@ -995,8 +996,8 @@ func ParseCircuitBandwidthEvent(raw string) *CircuitBandwidthEvent {
|
|||
ok := true
|
||||
var attr string
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "ID":
|
||||
event.CircuitID = val
|
||||
|
@ -1038,14 +1039,14 @@ func ParseCellStatsEvent(raw string) *CellStatsEvent {
|
|||
toIntMap := func(val string) map[string]int {
|
||||
ret := map[string]int{}
|
||||
for _, v := range strings.Split(val, ",") {
|
||||
key, val, _ := util.PartitionString(v, ':')
|
||||
key, val, _ := torutil.PartitionString(v, ':')
|
||||
ret[key], _ = strconv.Atoi(val)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "ID":
|
||||
event.CircuitID = val
|
||||
|
@ -1091,11 +1092,11 @@ type TokenBucketEmptyEvent struct {
|
|||
func ParseTokenBucketEmptyEvent(raw string) *TokenBucketEmptyEvent {
|
||||
event := &TokenBucketEmptyEvent{Raw: raw}
|
||||
var ok bool
|
||||
event.BucketName, raw, ok = util.PartitionString(raw, ' ')
|
||||
event.BucketName, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
var attr string
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, _ := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, _ := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "ID":
|
||||
event.ConnID = val
|
||||
|
@ -1132,16 +1133,16 @@ type HSDescEvent struct {
|
|||
// ParseHSDescEvent parses the event.
|
||||
func ParseHSDescEvent(raw string) *HSDescEvent {
|
||||
event := &HSDescEvent{Raw: raw}
|
||||
event.Action, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Address, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.AuthType, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Action, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.Address, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.AuthType, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
var ok bool
|
||||
event.HSDir, raw, ok = util.PartitionString(raw, ' ')
|
||||
event.HSDir, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
var attr string
|
||||
first := true
|
||||
for ok {
|
||||
attr, raw, ok = util.PartitionString(raw, ' ')
|
||||
key, val, valOk := util.PartitionString(attr, '=')
|
||||
attr, raw, ok = torutil.PartitionString(raw, ' ')
|
||||
key, val, valOk := torutil.PartitionString(attr, '=')
|
||||
switch key {
|
||||
case "REASON":
|
||||
event.Reason = val
|
||||
|
@ -1174,8 +1175,8 @@ type HSDescContentEvent struct {
|
|||
// ParseHSDescContentEvent parses the event.
|
||||
func ParseHSDescContentEvent(raw string) *HSDescContentEvent {
|
||||
event := &HSDescContentEvent{Raw: raw}
|
||||
event.Address, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.DescID, raw, _ = util.PartitionString(raw, ' ')
|
||||
event.Address, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
event.DescID, raw, _ = torutil.PartitionString(raw, ' ')
|
||||
newlineIndex := strings.Index(raw, "\r\n")
|
||||
if newlineIndex != -1 {
|
||||
event.HSDir, event.Descriptor = raw[:newlineIndex], raw[newlineIndex+2:]
|
||||
|
|
|
@ -3,7 +3,7 @@ package control
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/util"
|
||||
"github.com/cretz/bine/torutil"
|
||||
)
|
||||
|
||||
// Signal invokes SIGNAL.
|
||||
|
@ -30,7 +30,7 @@ func (c *Conn) MapAddresses(addresses ...*KeyVal) ([]*KeyVal, error) {
|
|||
ret := make([]*KeyVal, 0, len(data))
|
||||
for _, address := range data {
|
||||
mappedAddress := &KeyVal{}
|
||||
mappedAddress.Key, mappedAddress.Val, _ = util.PartitionString(address, '=')
|
||||
mappedAddress.Key, mappedAddress.Val, _ = torutil.PartitionString(address, '=')
|
||||
ret = append(ret, mappedAddress)
|
||||
}
|
||||
return ret, nil
|
||||
|
@ -45,8 +45,8 @@ func (c *Conn) GetInfo(keys ...string) ([]*KeyVal, error) {
|
|||
ret := make([]*KeyVal, 0, len(resp.Data))
|
||||
for _, val := range resp.Data {
|
||||
infoVal := &KeyVal{}
|
||||
infoVal.Key, infoVal.Val, _ = util.PartitionString(val, '=')
|
||||
if infoVal.Val, err = util.UnescapeSimpleQuotedStringIfNeeded(infoVal.Val); err != nil {
|
||||
infoVal.Key, infoVal.Val, _ = torutil.PartitionString(val, '=')
|
||||
if infoVal.Val, err = torutil.UnescapeSimpleQuotedStringIfNeeded(infoVal.Val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, infoVal)
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/util"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
"github.com/cretz/bine/torutil"
|
||||
"github.com/cretz/bine/torutil/ed25519"
|
||||
)
|
||||
|
||||
// KeyType is a key type for Key in AddOnion.
|
||||
|
@ -47,7 +47,7 @@ type Key interface {
|
|||
|
||||
// KeyFromString creates a Key for AddOnion based on a response string.
|
||||
func KeyFromString(str string) (Key, error) {
|
||||
typ, blob, _ := util.PartitionString(str, ':')
|
||||
typ, blob, _ := torutil.PartitionString(str, ':')
|
||||
switch KeyType(typ) {
|
||||
case KeyTypeNew:
|
||||
return GenKeyFromBlob(blob), nil
|
||||
|
@ -176,7 +176,7 @@ func (c *Conn) AddOnion(req *AddOnionRequest) (*AddOnionResponse, error) {
|
|||
}
|
||||
ret := &AddOnionResponse{RawResponse: resp}
|
||||
for _, data := range resp.Data {
|
||||
key, val, _ := util.PartitionString(data, '=')
|
||||
key, val, _ := torutil.PartitionString(data, '=')
|
||||
switch key {
|
||||
case "ServiceID":
|
||||
ret.ServiceID = val
|
||||
|
@ -185,7 +185,7 @@ func (c *Conn) AddOnion(req *AddOnionRequest) (*AddOnionResponse, error) {
|
|||
return nil, err
|
||||
}
|
||||
case "ClientAuth":
|
||||
name, pass, _ := util.PartitionString(val, ':')
|
||||
name, pass, _ := torutil.PartitionString(val, ':')
|
||||
if ret.ClientAuths == nil {
|
||||
ret.ClientAuths = map[string]string{}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package control
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/util"
|
||||
"github.com/cretz/bine/torutil"
|
||||
)
|
||||
|
||||
// ProtocolInfo is the protocol info result of Conn.ProtocolInfo.
|
||||
|
@ -42,7 +42,7 @@ func (c *Conn) sendProtocolInfo() (*ProtocolInfo, error) {
|
|||
// Check data vals
|
||||
ret := &ProtocolInfo{RawResponse: resp}
|
||||
for _, piece := range resp.Data {
|
||||
key, val, ok := util.PartitionString(piece, ' ')
|
||||
key, val, ok := torutil.PartitionString(piece, ' ')
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ func (c *Conn) sendProtocolInfo() (*ProtocolInfo, error) {
|
|||
return nil, c.protoErr("Invalid PIVERSION: %v", val)
|
||||
}
|
||||
case "AUTH":
|
||||
methods, cookieFile, _ := util.PartitionString(val, ' ')
|
||||
methods, cookieFile, _ := torutil.PartitionString(val, ' ')
|
||||
if !strings.HasPrefix(methods, "METHODS=") {
|
||||
continue
|
||||
}
|
||||
|
@ -60,15 +60,15 @@ func (c *Conn) sendProtocolInfo() (*ProtocolInfo, error) {
|
|||
if !strings.HasPrefix(cookieFile, "COOKIEFILE=") {
|
||||
continue
|
||||
}
|
||||
if ret.CookieFile, err = util.UnescapeSimpleQuotedString(cookieFile[11:]); err != nil {
|
||||
if ret.CookieFile, err = torutil.UnescapeSimpleQuotedString(cookieFile[11:]); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
ret.AuthMethods = strings.Split(methods[8:], ",")
|
||||
case "VERSION":
|
||||
torVersion, _, _ := util.PartitionString(val, ' ')
|
||||
torVersion, _, _ := torutil.PartitionString(val, ' ')
|
||||
if strings.HasPrefix(torVersion, "Tor=") {
|
||||
ret.TorVersion, err = util.UnescapeSimpleQuotedString(torVersion[4:])
|
||||
ret.TorVersion, err = torutil.UnescapeSimpleQuotedString(torVersion[4:])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/util"
|
||||
"github.com/cretz/bine/torutil"
|
||||
)
|
||||
|
||||
// Process is the interface implemented by Tor processes.
|
||||
|
@ -54,7 +54,7 @@ func (e *exeProcessCreator) New(ctx context.Context, args ...string) (Process, e
|
|||
// when ControlPortWriteToFile is set.
|
||||
func ControlPortFromFileContents(contents string) (int, error) {
|
||||
contents = strings.TrimSpace(contents)
|
||||
_, port, ok := util.PartitionString(contents, ':')
|
||||
_, port, ok := torutil.PartitionString(contents, ':')
|
||||
if !ok || !strings.HasPrefix(contents, "PORT=") {
|
||||
return 0, fmt.Errorf("Invalid port format: %v", contents)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/cretz/bine/tor"
|
||||
"github.com/cretz/bine/torutil"
|
||||
)
|
||||
|
||||
func TestListenSimpleHTTPV2(t *testing.T) {
|
||||
|
@ -17,12 +18,31 @@ func TestListenSimpleHTTPV2(t *testing.T) {
|
|||
_, err := w.Write([]byte("Test Content"))
|
||||
ctx.Require.NoError(err)
|
||||
})
|
||||
// Check the service ID
|
||||
ctx.Require.Equal(torutil.OnionServiceIDFromPrivateKey(onion.Key), onion.ID)
|
||||
defer server.Shutdown(ctx)
|
||||
// Call /test
|
||||
byts := httpGet(ctx, client, "http://"+onion.ID+".onion/test")
|
||||
ctx.Require.Equal("Test Content", string(byts))
|
||||
}
|
||||
|
||||
func TestListenSimpleHTTPV3(t *testing.T) {
|
||||
ctx := GlobalEnabledNetworkContext(t)
|
||||
// Create an onion service to listen on random port but show as 80
|
||||
conf := &tor.ListenConf{RemotePorts: []int{80}, Version3: true}
|
||||
// _, conf.Key, _ = ed25519.GenerateKey(nil)
|
||||
client, server, onion := startHTTPServer(ctx, conf, "/test", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, err := w.Write([]byte("Test Content"))
|
||||
ctx.Require.NoError(err)
|
||||
})
|
||||
defer server.Shutdown(ctx)
|
||||
// Check the service ID
|
||||
ctx.Require.Equal(torutil.OnionServiceIDFromPrivateKey(onion.Key), onion.ID)
|
||||
// Call /test
|
||||
byts := httpGet(ctx, client, "http://"+onion.ID+".onion/test")
|
||||
ctx.Require.Equal("Test Content", string(byts))
|
||||
}
|
||||
|
||||
// Only have to shutdown the HTTP server
|
||||
func startHTTPServer(
|
||||
ctx *TestContext,
|
||||
|
|
|
@ -8,9 +8,9 @@ import (
|
|||
"net"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/crypto/ed25519"
|
||||
|
||||
"github.com/cretz/bine/control"
|
||||
"github.com/cretz/bine/torutil/ed25519"
|
||||
othered25519 "golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
// OnionService implements net.Listener and net.Addr for an onion service.
|
||||
|
@ -21,7 +21,7 @@ type OnionService struct {
|
|||
// Key is the private key for this service. It is either the set key, the
|
||||
// generated key, or nil if asked to discard the key. If present, it is
|
||||
// *crypto/rsa.PrivateKey (1024 bit) when Version3 is false or
|
||||
// golang.org/x/crypto/ed25519.PrivateKey when Version3 is true.
|
||||
// github.com/cretz/bine/torutil/ed25519.PrivateKey when Version3 is true.
|
||||
Key crypto.PrivateKey
|
||||
|
||||
// Version3 says whether or not this service is a V3 service.
|
||||
|
@ -66,6 +66,7 @@ type ListenConf struct {
|
|||
// Key is the private key to use. If not present, a key is generated based
|
||||
// on whether Version3 is true or false. If present, it must be a
|
||||
// *crypto/rsa.PrivateKey (1024 bit), a
|
||||
// github.com/cretz/bine/torutil/ed25519.PrivateKey, a
|
||||
// golang.org/x/crypto/ed25519.PrivateKey, or a
|
||||
// github.com/cretz/bine/control.Key.
|
||||
Key crypto.PrivateKey
|
||||
|
@ -119,7 +120,7 @@ func (t *Tor) Listen(ctx context.Context, conf *ListenConf) (*OnionService, erro
|
|||
ctx = context.Background()
|
||||
}
|
||||
// Create the service up here and make sure we close it no matter the error within
|
||||
svc := &OnionService{Tor: t, Key: conf.Key, CloseLocalListenerOnClose: conf.LocalListener == nil}
|
||||
svc := &OnionService{Tor: t, CloseLocalListenerOnClose: conf.LocalListener == nil}
|
||||
var err error
|
||||
|
||||
// Create the local listener if necessary
|
||||
|
@ -159,16 +160,38 @@ func (t *Tor) Listen(ctx context.Context, conf *ListenConf) (*OnionService, erro
|
|||
} else {
|
||||
req.Key = control.GenKey(control.KeyAlgoRSA1024)
|
||||
}
|
||||
case control.GenKey:
|
||||
svc.Version3 = conf.Version3
|
||||
req.Key = key
|
||||
case *rsa.PrivateKey:
|
||||
svc.Key = key
|
||||
svc.Version3 = false
|
||||
if key.N == nil || key.N.BitLen() != 1024 {
|
||||
err = fmt.Errorf("RSA key must be 1024 bits")
|
||||
} else {
|
||||
req.Key = &control.RSAKey{PrivateKey: key}
|
||||
}
|
||||
case *control.RSAKey:
|
||||
svc.Key = key.PrivateKey
|
||||
svc.Version3 = false
|
||||
if key.N == nil || key.N.BitLen() != 1024 {
|
||||
err = fmt.Errorf("RSA key must be 1024 bits")
|
||||
} else {
|
||||
req.Key = key
|
||||
}
|
||||
case ed25519.PrivateKey:
|
||||
svc.Key = key
|
||||
svc.Version3 = true
|
||||
req.Key = control.ED25519Key(key)
|
||||
case othered25519.PrivateKey:
|
||||
properKey := ed25519.FromCryptoPrivateKey(key)
|
||||
svc.Key = properKey
|
||||
svc.Version3 = true
|
||||
req.Key = control.ED25519Key(properKey)
|
||||
case control.ED25519Key:
|
||||
svc.Key = ed25519.PrivateKey(key)
|
||||
svc.Version3 = true
|
||||
req.Key = key
|
||||
default:
|
||||
err = fmt.Errorf("Unrecognized key type: %T", key)
|
||||
}
|
||||
|
|
|
@ -288,7 +288,7 @@ func (t *Tor) EnableNetwork(ctx context.Context, wait bool) error {
|
|||
if status, _ := evt.(*control.StatusEvent); status != nil && status.Action == "BOOTSTRAP" {
|
||||
if status.Severity == "NOTICE" && status.Arguments["PROGRESS"] == "100" {
|
||||
return true, nil
|
||||
} else if status.Severity != "NOTICE" {
|
||||
} else if status.Severity == "ERR" {
|
||||
return false, fmt.Errorf("Failing bootstrapping, Tor warning: %v", status.Arguments["WARNING"])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
// Package torutil has generic utilities shared across the library.
|
||||
package torutil
|
|
@ -0,0 +1,78 @@
|
|||
// Package ed25519 implements Tor/BitTorrent-like ed25519 keys.
|
||||
//
|
||||
// See the following stack overflow post for details on why
|
||||
// golang.org/x/crypto/ed25519 can't be used:
|
||||
// https://stackoverflow.com/questions/44810708/ed25519-public-result-is-different
|
||||
package ed25519
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/cretz/bine/torutil/ed25519/edwards25519"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
// Ref: https://stackoverflow.com/questions/44810708/ed25519-public-result-is-different
|
||||
|
||||
// PrivateKey is a 64-byte Ed25519 private key.
|
||||
type PrivateKey []byte
|
||||
|
||||
// PublicKey is a 32-byte Ed25519 public key.
|
||||
type PublicKey []byte
|
||||
|
||||
// FromCryptoPrivateKey converts a Go private key to the one in this package.
|
||||
func FromCryptoPrivateKey(key ed25519.PrivateKey) PrivateKey {
|
||||
digest := sha512.Sum512(key[:32])
|
||||
digest[0] &= 248
|
||||
digest[31] &= 127
|
||||
digest[31] |= 64
|
||||
return digest[:]
|
||||
}
|
||||
|
||||
// FromCryptoPublicKey converts a Go public key to the one in this package.
|
||||
func FromCryptoPublicKey(key ed25519.PublicKey) PublicKey {
|
||||
return PublicKey(key)
|
||||
}
|
||||
|
||||
func (p PrivateKey) Public() crypto.PublicKey {
|
||||
return p.PublicKey()
|
||||
}
|
||||
|
||||
func (p PrivateKey) PublicKey() PublicKey {
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
var hBytes [32]byte
|
||||
copy(hBytes[:], p[:])
|
||||
edwards25519.GeScalarMultBase(&A, &hBytes)
|
||||
var publicKeyBytes [32]byte
|
||||
A.ToBytes(&publicKeyBytes)
|
||||
return publicKeyBytes[:]
|
||||
}
|
||||
|
||||
func (p PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
|
||||
if opts.HashFunc() != crypto.Hash(0) {
|
||||
return nil, errors.New("ed25519: cannot sign hashed message")
|
||||
}
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
// GenerateKey generates a public/private key pair using entropy from rand.
|
||||
// If rand is nil, crypto/rand.Reader will be used.
|
||||
func GenerateKey(rnd io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) {
|
||||
if rnd == nil {
|
||||
rnd = rand.Reader
|
||||
}
|
||||
_, err = io.ReadFull(rnd, privateKey[:32])
|
||||
if err == nil {
|
||||
digest := sha512.Sum512(privateKey[:32])
|
||||
digest[0] &= 248
|
||||
digest[31] &= 127
|
||||
digest[31] |= 64
|
||||
privateKey = digest[:]
|
||||
publicKey = privateKey.PublicKey()
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
This is taken from https://github.com/golang/crypto/tree/1a580b3eff7814fc9b40602fd35256c63b50f491/ed25519/internal/edwards25519
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
|||
package torutil
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/torutil/ed25519"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
var serviceIDEncoding = base32.StdEncoding.WithPadding(base32.NoPadding)
|
||||
|
||||
func OnionServiceIDFromPrivateKey(key crypto.PrivateKey) string {
|
||||
switch k := key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return OnionServiceIDFromV2PublicKey(&k.PublicKey)
|
||||
case ed25519.PrivateKey:
|
||||
return OnionServiceIDFromV3PublicKey(k.PublicKey())
|
||||
}
|
||||
panic(fmt.Sprintf("Unrecognized private key type: %T", key))
|
||||
}
|
||||
|
||||
func OnionServiceIDFromPublicKey(key crypto.PublicKey) string {
|
||||
switch k := key.(type) {
|
||||
case *rsa.PublicKey:
|
||||
return OnionServiceIDFromV2PublicKey(k)
|
||||
case ed25519.PublicKey:
|
||||
return OnionServiceIDFromV3PublicKey(k)
|
||||
}
|
||||
panic(fmt.Sprintf("Unrecognized private key type: %T", key))
|
||||
}
|
||||
|
||||
func OnionServiceIDFromV2PublicKey(key *rsa.PublicKey) string {
|
||||
h := sha1.New()
|
||||
h.Write(x509.MarshalPKCS1PublicKey(key))
|
||||
return strings.ToLower(serviceIDEncoding.EncodeToString(h.Sum(nil)[:10]))
|
||||
}
|
||||
|
||||
func OnionServiceIDFromV3PublicKey(key ed25519.PublicKey) string {
|
||||
checkSum := sha3.Sum256(append(append([]byte(".onion checksum"), key...), 0x03))
|
||||
var keyBytes [35]byte
|
||||
copy(keyBytes[:], key)
|
||||
keyBytes[32] = checkSum[0]
|
||||
keyBytes[33] = checkSum[1]
|
||||
keyBytes[34] = 0x03
|
||||
return strings.ToLower(serviceIDEncoding.EncodeToString(keyBytes[:]))
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package util
|
||||
package torutil
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,2 +0,0 @@
|
|||
// Package util has generic utilities shared across the library.
|
||||
package util
|
Loading…
Reference in New Issue