feat: upgrade syncthing version

This commit is contained in:
naison
2024-10-09 11:57:22 +00:00
parent 4d075b29b3
commit 605fe047ca
798 changed files with 57663 additions and 29024 deletions

View File

@@ -143,7 +143,8 @@ func DialWithTLSConfig(tc *tls.Config) DialOpt {
// DialWithTLSDialer is a wrapper for DialWithTLSConfig with the option to
// specify a net.Dialer to for example define a timeout or a custom resolver.
// @deprecated Use DialWithDialer and DialWithTLSConfig instead
//
// Deprecated: Use DialWithDialer and DialWithTLSConfig instead
func DialWithTLSDialer(tlsConfig *tls.Config, dialer *net.Dialer) DialOpt {
return func(dc *DialContext) {
dc.tlsConfig = tlsConfig
@@ -195,7 +196,8 @@ func (dc *DialContext) dial(u *url.URL) (net.Conn, error) {
// Dial connects to the given address on the given network using net.Dial
// and then returns a new Conn for the connection.
// @deprecated Use DialURL instead.
//
// Deprecated: Use DialURL instead.
func Dial(network, addr string) (*Conn, error) {
c, err := net.DialTimeout(network, addr, DefaultTimeout)
if err != nil {
@@ -208,7 +210,8 @@ func Dial(network, addr string) (*Conn, error) {
// DialTLS connects to the given address on the given network using tls.Dial
// and then returns a new Conn for the connection.
// @deprecated Use DialURL instead.
//
// Deprecated: Use DialURL instead.
func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
c, err := tls.DialWithDialer(&net.Dialer{Timeout: DefaultTimeout}, network, addr, config)
if err != nil {
@@ -262,7 +265,11 @@ func NewConn(conn net.Conn, isTLS bool) *Conn {
return l
}
// Start initializes goroutines to read responses and process messages
// Start initialises goroutines to read replies and process messages.
// Warning: Calling this function in addition to Dial or DialURL
// may cause race conditions.
//
// See: https://github.com/go-ldap/ldap/issues/356
func (l *Conn) Start() {
go l.reader()
go l.processMessages()

View File

@@ -635,7 +635,7 @@ type ControlDirSync struct {
Cookie []byte
}
// @deprecated Use NewRequestControlDirSync instead
// Deprecated: Use NewRequestControlDirSync instead
func NewControlDirSync(flags int64, maxAttrCount int64, cookie []byte) *ControlDirSync {
return NewRequestControlDirSync(flags, maxAttrCount, cookie)
}

View File

@@ -1,14 +1,14 @@
package ldap
import (
"bytes"
enchex "encoding/hex"
"encoding/hex"
"errors"
"fmt"
ber "github.com/go-asn1-ber/asn1-ber"
"sort"
"strings"
ber "github.com/go-asn1-ber/asn1-ber"
"unicode"
"unicode/utf8"
)
// AttributeTypeAndValue represents an attributeTypeAndValue from https://tools.ietf.org/html/rfc4514
@@ -19,62 +19,45 @@ type AttributeTypeAndValue struct {
Value string
}
// String returns a normalized string representation of this attribute type and
// value pair which is the a lowercased join of the Type and Value with a "=".
func (a *AttributeTypeAndValue) String() string {
return strings.ToLower(a.Type) + "=" + a.encodeValue()
func (a *AttributeTypeAndValue) setType(str string) error {
result, err := decodeString(str)
if err != nil {
return err
}
a.Type = result
return nil
}
func (a *AttributeTypeAndValue) encodeValue() string {
// Normalize the value first.
// value := strings.ToLower(a.Value)
value := a.Value
func (a *AttributeTypeAndValue) setValue(s string) error {
// https://www.ietf.org/rfc/rfc4514.html#section-2.4
// If the AttributeType is of the dotted-decimal form, the
// AttributeValue is represented by an number sign ('#' U+0023)
// character followed by the hexadecimal encoding of each of the octets
// of the BER encoding of the X.500 AttributeValue.
if len(s) > 0 && s[0] == '#' {
decodedString, err := decodeEncodedString(s[1:])
if err != nil {
return err
}
encodedBuf := bytes.Buffer{}
a.Value = decodedString
return nil
} else {
decodedString, err := decodeString(s)
if err != nil {
return err
}
escapeChar := func(c byte) {
encodedBuf.WriteByte('\\')
encodedBuf.WriteByte(c)
a.Value = decodedString
return nil
}
}
escapeHex := func(c byte) {
encodedBuf.WriteByte('\\')
encodedBuf.WriteString(enchex.EncodeToString([]byte{c}))
}
for i := 0; i < len(value); i++ {
char := value[i]
if i == 0 && char == ' ' || char == '#' {
// Special case leading space or number sign.
escapeChar(char)
continue
}
if i == len(value)-1 && char == ' ' {
// Special case trailing space.
escapeChar(char)
continue
}
switch char {
case '"', '+', ',', ';', '<', '>', '\\':
// Each of these special characters must be escaped.
escapeChar(char)
continue
}
if char < ' ' || char > '~' {
// All special character escapes are handled first
// above. All bytes less than ASCII SPACE and all bytes
// greater than ASCII TILDE must be hex-escaped.
escapeHex(char)
continue
}
// Any other character does not require escaping.
encodedBuf.WriteByte(char)
}
return encodedBuf.String()
// String returns a normalized string representation of this attribute type and
// value pair which is the lowercase join of the Type and Value with a "=".
func (a *AttributeTypeAndValue) String() string {
return encodeString(foldString(a.Type), false) + "=" + encodeString(a.Value, true)
}
// RelativeDN represents a relativeDistinguishedName from https://tools.ietf.org/html/rfc4514
@@ -108,114 +91,218 @@ func (d *DN) String() string {
return strings.Join(rdns, ",")
}
func stripLeadingAndTrailingSpaces(inVal string) string {
noSpaces := strings.Trim(inVal, " ")
// Re-add the trailing space if it was an escaped space
if len(noSpaces) > 0 && noSpaces[len(noSpaces)-1] == '\\' && inVal[len(inVal)-1] == ' ' {
noSpaces = noSpaces + " "
}
return noSpaces
}
// Remove leading and trailing spaces from the attribute type and value
// and unescape any escaped characters in these fields
//
// decodeString is based on https://github.com/inteon/cert-manager/blob/ed280d28cd02b262c5db46054d88e70ab518299c/pkg/util/pki/internal/dn.go#L170
func decodeString(str string) (string, error) {
s := []rune(stripLeadingAndTrailingSpaces(str))
builder := strings.Builder{}
for i := 0; i < len(s); i++ {
char := s[i]
// If the character is not an escape character, just add it to the
// builder and continue
if char != '\\' {
builder.WriteRune(char)
continue
}
// If the escape character is the last character, it's a corrupted
// escaped character
if i+1 >= len(s) {
return "", fmt.Errorf("got corrupted escaped character: '%s'", string(s))
}
// If the escaped character is a special character, just add it to
// the builder and continue
switch s[i+1] {
case ' ', '"', '#', '+', ',', ';', '<', '=', '>', '\\':
builder.WriteRune(s[i+1])
i++
continue
}
// If the escaped character is not a special character, it should
// be a hex-encoded character of the form \XX if it's not at least
// two characters long, it's a corrupted escaped character
if i+2 >= len(s) {
return "", errors.New("failed to decode escaped character: encoding/hex: invalid byte: " + string(s[i+1]))
}
// Get the runes for the two characters after the escape character
// and convert them to a byte slice
xx := []byte(string(s[i+1 : i+3]))
// If the two runes are not hex characters and result in more than
// two bytes when converted to a byte slice, it's a corrupted
// escaped character
if len(xx) != 2 {
return "", errors.New("failed to decode escaped character: invalid byte: " + string(xx))
}
// Decode the hex-encoded character and add it to the builder
dst := []byte{0}
if n, err := hex.Decode(dst, xx); err != nil {
return "", errors.New("failed to decode escaped character: " + err.Error())
} else if n != 1 {
return "", fmt.Errorf("failed to decode escaped character: encoding/hex: expected 1 byte when un-escaping, got %d", n)
}
builder.WriteByte(dst[0])
i += 2
}
return builder.String(), nil
}
// Escape a string according to RFC 4514
func encodeString(value string, isValue bool) string {
builder := strings.Builder{}
escapeChar := func(c byte) {
builder.WriteByte('\\')
builder.WriteByte(c)
}
escapeHex := func(c byte) {
builder.WriteByte('\\')
builder.WriteString(hex.EncodeToString([]byte{c}))
}
// Loop through each byte and escape as necessary.
// Runes that take up more than one byte are escaped
// byte by byte (since both bytes are non-ASCII).
for i := 0; i < len(value); i++ {
char := value[i]
if i == 0 && (char == ' ' || char == '#') {
// Special case leading space or number sign.
escapeChar(char)
continue
}
if i == len(value)-1 && char == ' ' {
// Special case trailing space.
escapeChar(char)
continue
}
switch char {
case '"', '+', ',', ';', '<', '>', '\\':
// Each of these special characters must be escaped.
escapeChar(char)
continue
}
if !isValue && char == '=' {
// Equal signs have to be escaped only in the type part of
// the attribute type and value pair.
escapeChar(char)
continue
}
if char < ' ' || char > '~' {
// All special character escapes are handled first
// above. All bytes less than ASCII SPACE and all bytes
// greater than ASCII TILDE must be hex-escaped.
escapeHex(char)
continue
}
// Any other character does not require escaping.
builder.WriteByte(char)
}
return builder.String()
}
func decodeEncodedString(str string) (string, error) {
decoded, err := hex.DecodeString(str)
if err != nil {
return "", fmt.Errorf("failed to decode BER encoding: %w", err)
}
packet, err := ber.DecodePacketErr(decoded)
if err != nil {
return "", fmt.Errorf("failed to decode BER encoding: %w", err)
}
return packet.Data.String(), nil
}
// ParseDN returns a distinguishedName or an error.
// The function respects https://tools.ietf.org/html/rfc4514
func ParseDN(str string) (*DN, error) {
dn := new(DN)
dn.RDNs = make([]*RelativeDN, 0)
rdn := new(RelativeDN)
rdn.Attributes = make([]*AttributeTypeAndValue, 0)
buffer := bytes.Buffer{}
attribute := new(AttributeTypeAndValue)
escaping := false
unescapedTrailingSpaces := 0
stringFromBuffer := func() string {
s := buffer.String()
s = s[0 : len(s)-unescapedTrailingSpaces]
buffer.Reset()
unescapedTrailingSpaces = 0
return s
var dn = &DN{RDNs: make([]*RelativeDN, 0)}
if strings.TrimSpace(str) == "" {
return dn, nil
}
var (
rdn = &RelativeDN{}
attr = &AttributeTypeAndValue{}
escaping bool
startPos int
appendAttributesToRDN = func(end bool) {
rdn.Attributes = append(rdn.Attributes, attr)
attr = &AttributeTypeAndValue{}
if end {
dn.RDNs = append(dn.RDNs, rdn)
rdn = &RelativeDN{}
}
}
)
// Loop through each character in the string and
// build up the attribute type and value pairs.
// We only check for ascii characters here, which
// allows us to iterate over the string byte by byte.
for i := 0; i < len(str); i++ {
char := str[i]
switch {
case escaping:
unescapedTrailingSpaces = 0
escaping = false
switch char {
case ' ', '"', '#', '+', ',', ';', '<', '=', '>', '\\':
buffer.WriteByte(char)
continue
case char == '\\':
escaping = true
case char == '=' && len(attr.Type) == 0:
if err := attr.setType(str[startPos:i]); err != nil {
return nil, err
}
// Not a special character, assume hex encoded octet
if len(str) == i+1 {
return nil, errors.New("got corrupted escaped character")
startPos = i + 1
case char == ',' || char == '+' || char == ';':
if len(attr.Type) == 0 {
return dn, errors.New("incomplete type, value pair")
}
if err := attr.setValue(str[startPos:i]); err != nil {
return nil, err
}
dst := []byte{0}
n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2]))
if err != nil {
return nil, fmt.Errorf("failed to decode escaped character: %s", err)
} else if n != 1 {
return nil, fmt.Errorf("expected 1 byte when un-escaping, got %d", n)
}
buffer.WriteByte(dst[0])
i++
case char == '\\':
unescapedTrailingSpaces = 0
escaping = true
case char == '=' && attribute.Type == "":
attribute.Type = stringFromBuffer()
// Special case: If the first character in the value is # the
// following data is BER encoded so we can just fast forward
// and decode.
if len(str) > i+1 && str[i+1] == '#' {
i += 2
index := strings.IndexAny(str[i:], ",+")
var data string
if index > 0 {
data = str[i : i+index]
} else {
data = str[i:]
}
rawBER, err := enchex.DecodeString(data)
if err != nil {
return nil, fmt.Errorf("failed to decode BER encoding: %s", err)
}
packet, err := ber.DecodePacketErr(rawBER)
if err != nil {
return nil, fmt.Errorf("failed to decode BER packet: %s", err)
}
buffer.WriteString(packet.Data.String())
i += len(data) - 1
}
case char == ',' || char == '+' || char == ';':
// We're done with this RDN or value, push it
if len(attribute.Type) == 0 {
return nil, errors.New("incomplete type, value pair")
}
attribute.Value = stringFromBuffer()
rdn.Attributes = append(rdn.Attributes, attribute)
attribute = new(AttributeTypeAndValue)
if char == ',' || char == ';' {
dn.RDNs = append(dn.RDNs, rdn)
rdn = new(RelativeDN)
rdn.Attributes = make([]*AttributeTypeAndValue, 0)
}
case char == ' ' && buffer.Len() == 0:
// ignore unescaped leading spaces
continue
default:
if char == ' ' {
// Track unescaped spaces in case they are trailing and we need to remove them
unescapedTrailingSpaces++
} else {
// Reset if we see a non-space char
unescapedTrailingSpaces = 0
}
buffer.WriteByte(char)
startPos = i + 1
last := char == ',' || char == ';'
appendAttributesToRDN(last)
}
}
if buffer.Len() > 0 {
if len(attribute.Type) == 0 {
return nil, errors.New("DN ended with incomplete type, value pair")
}
attribute.Value = stringFromBuffer()
rdn.Attributes = append(rdn.Attributes, attribute)
dn.RDNs = append(dn.RDNs, rdn)
if len(attr.Type) == 0 {
return dn, errors.New("DN ended with incomplete type, value pair")
}
if err := attr.setValue(str[startPos:]); err != nil {
return dn, err
}
appendAttributesToRDN(true)
return dn, nil
}
@@ -348,3 +435,34 @@ func (r *RelativeDN) hasAllAttributesFold(attrs []*AttributeTypeAndValue) bool {
func (a *AttributeTypeAndValue) EqualFold(other *AttributeTypeAndValue) bool {
return strings.EqualFold(a.Type, other.Type) && strings.EqualFold(a.Value, other.Value)
}
// foldString returns a folded string such that foldString(x) == foldString(y)
// is identical to bytes.EqualFold(x, y).
// based on https://go.dev/src/encoding/json/fold.go
func foldString(s string) string {
builder := strings.Builder{}
for _, char := range s {
// Handle single-byte ASCII.
if char < utf8.RuneSelf {
if 'A' <= char && char <= 'Z' {
char += 'a' - 'A'
}
builder.WriteRune(char)
continue
}
builder.WriteRune(foldRune(char))
}
return builder.String()
}
// foldRune is returns the smallest rune for all runes in the same fold set.
func foldRune(r rune) rune {
for {
r2 := unicode.SimpleFold(r)
if r2 <= r {
return r
}
r = r2
}
}

View File

@@ -1,6 +1,7 @@
package ldap
import (
"errors"
"fmt"
ber "github.com/go-asn1-ber/asn1-ber"
@@ -241,8 +242,8 @@ func IsErrorAnyOf(err error, codes ...uint16) bool {
return false
}
serverError, ok := err.(*Error)
if !ok {
var serverError *Error
if !errors.As(err, &serverError) {
return false
}

View File

@@ -314,8 +314,6 @@ func DebugBinaryFile(fileName string) error {
return nil
}
var hex = "0123456789abcdef"
func mustEscape(c byte) bool {
return c > 0x7f || c == '(' || c == ')' || c == '\\' || c == '*' || c == 0
}
@@ -324,6 +322,7 @@ func mustEscape(c byte) bool {
// characters in the set `()*\` and those out of the range 0 < c < 0x80,
// as defined in RFC4515.
func EscapeFilter(filter string) string {
const hexValues = "0123456789abcdef"
escape := 0
for i := 0; i < len(filter); i++ {
if mustEscape(filter[i]) {
@@ -338,8 +337,8 @@ func EscapeFilter(filter string) string {
c := filter[i]
if mustEscape(c) {
buf[j+0] = '\\'
buf[j+1] = hex[c>>4]
buf[j+2] = hex[c&0xf]
buf[j+1] = hexValues[c>>4]
buf[j+2] = hexValues[c&0xf]
j += 3
} else {
buf[j] = c

View File

@@ -98,13 +98,12 @@ func (r *searchResponse) start(ctx context.Context, searchRequest *SearchRequest
foundSearchSingleResultDone := false
for !foundSearchSingleResultDone {
r.conn.Debug.Printf("%d: waiting for response", msgCtx.id)
select {
case <-ctx.Done():
r.conn.Debug.Printf("%d: %s", msgCtx.id, ctx.Err().Error())
return
default:
r.conn.Debug.Printf("%d: waiting for response", msgCtx.id)
packetResponse, ok := <-msgCtx.responses
case packetResponse, ok := <-msgCtx.responses:
if !ok {
err := NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
r.ch <- &SearchSingleResult{Error: err}

View File

@@ -18,6 +18,9 @@ const (
ScopeBaseObject = 0
ScopeSingleLevel = 1
ScopeWholeSubtree = 2
// ScopeChildren is an OpenLDAP extension that may not be supported by another directory server.
// See: https://github.com/openldap/openldap/blob/7c55484ee153047efd0e562fc1638c1a2525f320/include/ldap.h#L598
ScopeChildren = 3
)
// ScopeMap contains human readable descriptions of scope choices
@@ -25,6 +28,7 @@ var ScopeMap = map[int]string{
ScopeBaseObject: "Base Object",
ScopeSingleLevel: "Single Level",
ScopeWholeSubtree: "Whole Subtree",
ScopeChildren: "Children",
}
// derefAliases
@@ -43,6 +47,10 @@ var DerefMap = map[int]string{
DerefAlways: "DerefAlways",
}
// ErrSizeLimitExceeded will be returned if the search result is exceeding the defined SizeLimit
// and enforcing the requested limit is enabled in the search request (EnforceSizeLimit)
var ErrSizeLimitExceeded = NewError(ErrorNetwork, errors.New("ldap: size limit exceeded"))
// NewEntry returns an Entry object with the specified distinguished name and attribute key-value pairs.
// The map of attributes is accessed in alphabetical order of the keys in order to ensure that, for the
// same input map of attributes, the output entry will contain the same order of attributes
@@ -187,8 +195,8 @@ func readTag(f reflect.StructField) (string, bool) {
// Unmarshal parses the Entry in the value pointed to by i
//
// Currently, this methods only supports struct fields of type
// string, []string, int, int64, []byte, *DN, []*DN or time.Time. Other field types
// will not be regarded. If the field type is a string or int but multiple
// string, *string, []string, int, int64, []byte, *DN, []*DN or time.Time.
// Other field types will not be regarded. If the field type is a string or int but multiple
// attribute values are returned, the first value will be used to fill the field.
//
// Example:
@@ -279,6 +287,8 @@ func (e *Entry) Unmarshal(i interface{}) (err error) {
}
case string:
fv.SetString(values[0])
case *string:
fv.Set(reflect.ValueOf(&values[0]))
case []byte:
fv.SetBytes([]byte(values[0]))
case int, int64:
@@ -308,7 +318,7 @@ func (e *Entry) Unmarshal(i interface{}) (err error) {
fv.Set(reflect.Append(fv, reflect.ValueOf(dn)))
}
default:
return fmt.Errorf("ldap: expected field to be of type string, []string, int, int64, []byte, *DN, []*DN or time.Time, got %v", ft.Type)
return fmt.Errorf("ldap: expected field to be of type string, *string, []string, int, int64, []byte, *DN, []*DN or time.Time, got %v", ft.Type)
}
}
return
@@ -411,6 +421,11 @@ type SearchRequest struct {
Filter string
Attributes []string
Controls []Control
// EnforceSizeLimit will hard limit the maximum number of entries parsed, in case the directory
// server returns more results than requested. This setting is disabled by default and does not
// work in async search requests.
EnforceSizeLimit bool
}
func (req *SearchRequest) appendTo(envelope *ber.Packet) error {
@@ -558,6 +573,12 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
switch packet.Children[1].Tag {
case 4:
if searchRequest.EnforceSizeLimit &&
searchRequest.SizeLimit > 0 &&
len(result.Entries) >= searchRequest.SizeLimit {
return result, ErrSizeLimitExceeded
}
entry := &Entry{
DN: packet.Children[1].Children[0].Value.(string),
Attributes: unpackAttributes(packet.Children[1].Children[1].Children),