Integrate BACKBEAT SDK and resolve KACHING license validation

Major integrations and fixes:
- Added BACKBEAT SDK integration for P2P operation timing
- Implemented beat-aware status tracking for distributed operations
- Added Docker secrets support for secure license management
- Resolved KACHING license validation via HTTPS/TLS
- Updated docker-compose configuration for clean stack deployment
- Disabled rollback policies to prevent deployment failures
- Added license credential storage (CHORUS-DEV-MULTI-001)

Technical improvements:
- BACKBEAT P2P operation tracking with phase management
- Enhanced configuration system with file-based secrets
- Improved error handling for license validation
- Clean separation of KACHING and CHORUS deployment stacks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-09-06 07:56:26 +10:00
parent 543ab216f9
commit 9bdcbe0447
4730 changed files with 1480093 additions and 1916 deletions

27
vendor/github.com/multiformats/go-base32/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

509
vendor/github.com/multiformats/go-base32/base32.go generated vendored Normal file
View File

@@ -0,0 +1,509 @@
// 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.
// Package base32 implements base32 encoding as specified by RFC 4648.
package base32
import (
"io"
"strconv"
)
/*
* Encodings
*/
// An Encoding is a radix 32 encoding/decoding scheme, defined by a
// 32-character alphabet. The most common is the "base32" encoding
// introduced for SASL GSSAPI and standardized in RFC 4648.
// The alternate "base32hex" encoding is used in DNSSEC.
type Encoding struct {
encode string
decodeMap [256]byte
padChar rune
}
// Alphabet returns the Base32 alphabet used
func (enc *Encoding) Alphabet() string {
return enc.encode
}
const (
StdPadding rune = '='
NoPadding rune = -1
)
const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
// NewEncoding returns a new Encoding defined by the given alphabet,
// which must be a 32-byte string.
func NewEncoding(encoder string) *Encoding {
e := new(Encoding)
e.padChar = StdPadding
e.encode = encoder
for i := 0; i < len(e.decodeMap); i++ {
e.decodeMap[i] = 0xFF
}
for i := 0; i < len(encoder); i++ {
e.decodeMap[encoder[i]] = byte(i)
}
return e
}
// NewEncoding returns a new case insensitive Encoding defined by the
// given alphabet, which must be a 32-byte string.
func NewEncodingCI(encoder string) *Encoding {
e := new(Encoding)
e.padChar = StdPadding
e.encode = encoder
for i := 0; i < len(e.decodeMap); i++ {
e.decodeMap[i] = 0xFF
}
for i := 0; i < len(encoder); i++ {
e.decodeMap[asciiToLower(encoder[i])] = byte(i)
e.decodeMap[asciiToUpper(encoder[i])] = byte(i)
}
return e
}
func asciiToLower(c byte) byte {
if c >= 'A' && c <= 'Z' {
return c + 32
}
return c
}
func asciiToUpper(c byte) byte {
if c >= 'a' && c <= 'z' {
return c - 32
}
return c
}
// WithPadding creates a new encoding identical to enc except
// with a specified padding character, or NoPadding to disable padding.
func (enc Encoding) WithPadding(padding rune) *Encoding {
enc.padChar = padding
return &enc
}
// StdEncoding is the standard base32 encoding, as defined in
// RFC 4648.
var StdEncoding = NewEncodingCI(encodeStd)
// HexEncoding is the “Extended Hex Alphabet” defined in RFC 4648.
// It is typically used in DNS.
var HexEncoding = NewEncodingCI(encodeHex)
var RawStdEncoding = NewEncodingCI(encodeStd).WithPadding(NoPadding)
var RawHexEncoding = NewEncodingCI(encodeHex).WithPadding(NoPadding)
/*
* Encoder
*/
// Encode encodes src using the encoding enc, writing
// EncodedLen(len(src)) bytes to dst.
//
// The encoding pads the output to a multiple of 8 bytes,
// so Encode is not appropriate for use on individual blocks
// of a large data stream. Use NewEncoder() instead.
func (enc *Encoding) Encode(dst, src []byte) {
if len(src) == 0 {
return
}
// Unpack 8x 5-bit source blocks into a 5 byte
// destination quantum
for len(src) > 4 {
dst[7] = enc.encode[src[4]&0x1F]
dst[6] = enc.encode[(src[4]>>5)|(src[3]<<3)&0x1F]
dst[5] = enc.encode[(src[3]>>2)&0x1F]
dst[4] = enc.encode[(src[3]>>7)|(src[2]<<1)&0x1F]
dst[3] = enc.encode[((src[2]>>4)|(src[1]<<4))&0x1F]
dst[2] = enc.encode[(src[1]>>1)&0x1F]
dst[1] = enc.encode[((src[1]>>6)|(src[0]<<2))&0x1F]
dst[0] = enc.encode[src[0]>>3]
src = src[5:]
dst = dst[8:]
}
var carry byte
switch len(src) {
case 4:
dst[6] = enc.encode[(src[3]<<3)&0x1F]
dst[5] = enc.encode[(src[3]>>2)&0x1F]
carry = src[3] >> 7
fallthrough
case 3:
dst[4] = enc.encode[carry|(src[2]<<1)&0x1F]
carry = (src[2] >> 4) & 0x1F
fallthrough
case 2:
dst[3] = enc.encode[carry|(src[1]<<4)&0x1F]
dst[2] = enc.encode[(src[1]>>1)&0x1F]
carry = (src[1] >> 6) & 0x1F
fallthrough
case 1:
dst[1] = enc.encode[carry|(src[0]<<2)&0x1F]
dst[0] = enc.encode[src[0]>>3]
case 0:
return
}
if enc.padChar != NoPadding {
dst[7] = byte(enc.padChar)
if len(src) < 4 {
dst[6] = byte(enc.padChar)
dst[5] = byte(enc.padChar)
if len(src) < 3 {
dst[4] = byte(enc.padChar)
if len(src) < 2 {
dst[3] = byte(enc.padChar)
dst[2] = byte(enc.padChar)
}
}
}
}
}
// EncodeToString returns the base32 encoding of src.
func (enc *Encoding) EncodeToString(src []byte) string {
buf := make([]byte, enc.EncodedLen(len(src)))
enc.Encode(buf, src)
return string(buf)
}
type encoder struct {
err error
enc *Encoding
w io.Writer
buf [5]byte // buffered data waiting to be encoded
nbuf int // number of bytes in buf
out [1024]byte // output buffer
}
func (e *encoder) Write(p []byte) (n int, err error) {
if e.err != nil {
return 0, e.err
}
// Leading fringe.
if e.nbuf > 0 {
var i int
for i = 0; i < len(p) && e.nbuf < 5; i++ {
e.buf[e.nbuf] = p[i]
e.nbuf++
}
n += i
p = p[i:]
if e.nbuf < 5 {
return
}
e.enc.Encode(e.out[0:], e.buf[0:])
if _, e.err = e.w.Write(e.out[0:8]); e.err != nil {
return n, e.err
}
e.nbuf = 0
}
// Large interior chunks.
for len(p) >= 5 {
nn := len(e.out) / 8 * 5
if nn > len(p) {
nn = len(p)
nn -= nn % 5
}
e.enc.Encode(e.out[0:], p[0:nn])
if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
return n, e.err
}
n += nn
p = p[nn:]
}
// Trailing fringe.
//lint:ignore S1001 fixed-length 5-byte slice
for i := 0; i < len(p); i++ {
e.buf[i] = p[i]
}
e.nbuf = len(p)
n += len(p)
return
}
// Close flushes any pending output from the encoder.
// It is an error to call Write after calling Close.
func (e *encoder) Close() error {
// If there's anything left in the buffer, flush it out
if e.err == nil && e.nbuf > 0 {
e.enc.Encode(e.out[0:], e.buf[0:e.nbuf])
e.nbuf = 0
_, e.err = e.w.Write(e.out[0:8])
}
return e.err
}
// NewEncoder returns a new base32 stream encoder. Data written to
// the returned writer will be encoded using enc and then written to w.
// Base32 encodings operate in 5-byte blocks; when finished
// writing, the caller must Close the returned encoder to flush any
// partially written blocks.
func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser {
return &encoder{enc: enc, w: w}
}
// EncodedLen returns the length in bytes of the base32 encoding
// of an input buffer of length n.
func (enc *Encoding) EncodedLen(n int) int {
if enc.padChar == NoPadding {
return (n*8 + 4) / 5 // minimum # chars at 5 bits per char
}
return (n + 4) / 5 * 8
}
/*
* Decoder
*/
type CorruptInputError int64
func (e CorruptInputError) Error() string {
return "illegal base32 data at input byte " + strconv.FormatInt(int64(e), 10)
}
// decode is like Decode but returns an additional 'end' value, which
// indicates if end-of-message padding was encountered and thus any
// additional data is an error. This method assumes that src has been
// stripped of all supported whitespace ('\r' and '\n').
func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
olen := len(src)
for len(src) > 0 && !end {
// Decode quantum using the base32 alphabet
var dbuf [8]byte
dlen := 8
for j := 0; j < 8; {
if len(src) == 0 {
if enc.padChar != NoPadding {
return n, false, CorruptInputError(olen - len(src) - j)
}
dlen = j
break
}
in := src[0]
src = src[1:]
if in == byte(enc.padChar) && j >= 2 && len(src) < 8 {
if enc.padChar == NoPadding {
return n, false, CorruptInputError(olen)
}
// We've reached the end and there's padding
if len(src)+j < 8-1 {
// not enough padding
return n, false, CorruptInputError(olen)
}
for k := 0; k < 8-1-j; k++ {
if len(src) > k && src[k] != byte(enc.padChar) {
// incorrect padding
return n, false, CorruptInputError(olen - len(src) + k - 1)
}
}
dlen, end = j, true
// 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not
// valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing
// the five valid padding lengths, and Section 9 "Illustrations and
// Examples" for an illustration for how the 1st, 3rd and 6th base32
// src bytes do not yield enough information to decode a dst byte.
if dlen == 1 || dlen == 3 || dlen == 6 {
return n, false, CorruptInputError(olen - len(src) - 1)
}
break
}
dbuf[j] = enc.decodeMap[in]
if dbuf[j] == 0xFF {
return n, false, CorruptInputError(olen - len(src) - 1)
}
j++
}
// Pack 8x 5-bit source blocks into 5 byte destination
// quantum
switch dlen {
case 8:
dst[4] = dbuf[6]<<5 | dbuf[7]
fallthrough
case 7:
dst[3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3
fallthrough
case 5:
dst[2] = dbuf[3]<<4 | dbuf[4]>>1
fallthrough
case 4:
dst[1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4
fallthrough
case 2:
dst[0] = dbuf[0]<<3 | dbuf[1]>>2
}
if len(dst) > 5 {
dst = dst[5:]
}
switch dlen {
case 2:
n += 1
case 4:
n += 2
case 5:
n += 3
case 7:
n += 4
case 8:
n += 5
}
}
return n, end, nil
}
// Decode decodes src using the encoding enc. It writes at most
// DecodedLen(len(src)) bytes to dst and returns the number of bytes
// written. If src contains invalid base32 data, it will return the
// number of bytes successfully written and CorruptInputError.
// New line characters (\r and \n) are ignored.
func (enc *Encoding) Decode(dst, s []byte) (n int, err error) {
// FIXME: if dst is the same as s use decodeInPlace
stripped := make([]byte, 0, len(s))
for _, c := range s {
if c != '\r' && c != '\n' {
stripped = append(stripped, c)
}
}
n, _, err = enc.decode(dst, stripped)
return
}
func (enc *Encoding) decodeInPlace(strb []byte) (n int, err error) {
off := 0
for _, b := range strb {
if b == '\n' || b == '\r' {
continue
}
strb[off] = b
off++
}
n, _, err = enc.decode(strb, strb[:off])
return
}
// DecodeString returns the bytes represented by the base32 string s.
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
strb := []byte(s)
n, err := enc.decodeInPlace(strb)
if err != nil {
return nil, err
}
return strb[:n], nil
}
type decoder struct {
err error
enc *Encoding
r io.Reader
end bool // saw end of message
buf [1024]byte // leftover input
nbuf int
out []byte // leftover decoded output
outbuf [1024 / 8 * 5]byte
}
func (d *decoder) Read(p []byte) (n int, err error) {
if d.err != nil {
return 0, d.err
}
// Use leftover decoded output from last read.
if len(d.out) > 0 {
n = copy(p, d.out)
d.out = d.out[n:]
return n, nil
}
// Read a chunk.
nn := len(p) / 5 * 8
if nn < 8 {
nn = 8
}
if nn > len(d.buf) {
nn = len(d.buf)
}
nn, d.err = io.ReadAtLeast(d.r, d.buf[d.nbuf:nn], 8-d.nbuf)
d.nbuf += nn
if d.nbuf < 8 {
return 0, d.err
}
// Decode chunk into p, or d.out and then p if p is too small.
nr := d.nbuf / 8 * 8
nw := d.nbuf / 8 * 5
if nw > len(p) {
nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
d.out = d.outbuf[0:nw]
n = copy(p, d.out)
d.out = d.out[n:]
} else {
n, d.end, d.err = d.enc.decode(p, d.buf[0:nr])
}
d.nbuf -= nr
for i := 0; i < d.nbuf; i++ {
d.buf[i] = d.buf[i+nr]
}
if d.err == nil {
d.err = err
}
return n, d.err
}
type newlineFilteringReader struct {
wrapped io.Reader
}
func (r *newlineFilteringReader) Read(p []byte) (int, error) {
n, err := r.wrapped.Read(p)
for n > 0 {
offset := 0
for i, b := range p[0:n] {
if b != '\r' && b != '\n' {
if i != offset {
p[offset] = b
}
offset++
}
}
if offset > 0 {
return offset, err
}
// Previous buffer entirely whitespace, read again
n, err = r.wrapped.Read(p)
}
return n, err
}
// NewDecoder constructs a new base32 stream decoder.
func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
return &decoder{enc: enc, r: &newlineFilteringReader{r}}
}
// DecodedLen returns the maximum length in bytes of the decoded data
// corresponding to n bytes of base32-encoded data.
func (enc *Encoding) DecodedLen(n int) int {
if enc.padChar == NoPadding {
return (n*5 + 7) / 8
}
return n / 8 * 5
}

15
vendor/github.com/multiformats/go-base32/package.json generated vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"author": "Golang",
"bugs": {
"url": "https://github.com/multiformats/go-base32"
},
"gx": {
"dvcsimport": "github.com/multiformats/go-base32"
},
"gxVersion": "0.7.0",
"language": "go",
"license": "BSD-3",
"name": "base32",
"version": "0.0.3"
}

View File

@@ -0,0 +1,3 @@
{
"version": "v0.1.0"
}

22
vendor/github.com/multiformats/go-base36/LICENSE.md generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The software contents of this repository are Copyright (c) Protocol Labs,
Licensed under the `Permissive License Stack`, meaning either of:
- Apache-2.0 Software License: https://www.apache.org/licenses/LICENSE-2.0
([...4tr2kfsq](https://gateway.ipfs.io/ipfs/bafkreiankqxazcae4onkp436wag2lj3ccso4nawxqkkfckd6cg4tr2kfsq))
- MIT Software License: https://opensource.org/licenses/MIT
([...vljevcba](https://gateway.ipfs.io/ipfs/bafkreiepofszg4gfe2gzuhojmksgemsub2h4uy2gewdnr35kswvljevcba))
You may not use the contents of this repository except in compliance
with one of the listed Licenses. For an extended clarification of the
intent behind the choice of Licensing please refer to
https://protocol.ai/blog/announcing-the-permissive-license-stack/
Unless required by applicable law or agreed to in writing, software
distributed under the terms listed in this notice is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied. See each License for the specific language
governing permissions and limitations under that License.
<!--- SPDX-License-Identifier: Apache-2.0 OR MIT -->
`SPDX-License-Identifier: Apache-2.0 OR MIT`

22
vendor/github.com/multiformats/go-base36/README.md generated vendored Normal file
View File

@@ -0,0 +1,22 @@
multiformats/go-base36
=======================
> Simple base36 codec
This is an optimized codec for []byte <=> base36 string conversion
## Documentation
https://pkg.go.dev/github.com/multiformats/go-base36
## Lead Maintainer
[Steven Allen](https://github.com/stebalien)
## Contributing
Contributions are welcome! This repository is related to the IPFS project and therefore governed by our [contributing guidelines](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md).
## License
[SPDX-License-Identifier: Apache-2.0 OR MIT](LICENSE.md)

143
vendor/github.com/multiformats/go-base36/base36.go generated vendored Normal file
View File

@@ -0,0 +1,143 @@
/*
Package base36 provides a reasonably fast implementation of a binary base36 codec.
*/
package base36
// Simplified code based on https://godoc.org/github.com/mr-tron/base58
// which in turn is based on https://github.com/trezor/trezor-crypto/commit/89a7d7797b806fac
import (
"fmt"
)
const UcAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
const LcAlphabet = "0123456789abcdefghijklmnopqrstuvwxyz"
const maxDigitOrdinal = 'z'
const maxDigitValueB36 = 35
var revAlphabet [maxDigitOrdinal + 1]byte
func init() {
for i := range revAlphabet {
revAlphabet[i] = maxDigitValueB36 + 1
}
for i, c := range UcAlphabet {
revAlphabet[byte(c)] = byte(i)
if c > '9' {
revAlphabet[byte(c)+32] = byte(i)
}
}
}
// EncodeToStringUc encodes the given byte-buffer as base36 using [0-9A-Z] as
// the digit-alphabet
func EncodeToStringUc(b []byte) string { return encode(b, UcAlphabet) }
// EncodeToStringLc encodes the given byte-buffer as base36 using [0-9a-z] as
// the digit-alphabet
func EncodeToStringLc(b []byte) string { return encode(b, LcAlphabet) }
func encode(inBuf []byte, al string) string {
bufsz := len(inBuf)
zcnt := 0
for zcnt < bufsz && inBuf[zcnt] == 0 {
zcnt++
}
// It is crucial to make this as short as possible, especially for
// the usual case of CIDs.
bufsz = zcnt +
// This is an integer simplification of
// ceil(log(256)/log(36))
(bufsz-zcnt)*277/179 + 1
// Note: pools *DO NOT* help, the overhead of zeroing
// kills any performance gain to be had
out := make([]byte, bufsz)
var idx, stopIdx int
var carry uint32
stopIdx = bufsz - 1
for _, b := range inBuf[zcnt:] {
idx = bufsz - 1
for carry = uint32(b); idx > stopIdx || carry != 0; idx-- {
carry += uint32((out[idx])) * 256
out[idx] = byte(carry % 36)
carry /= 36
}
stopIdx = idx
}
// Determine the additional "zero-gap" in the buffer (aside from zcnt)
for stopIdx = zcnt; stopIdx < bufsz && out[stopIdx] == 0; stopIdx++ {
}
// Now encode the values with actual alphabet in-place
vBuf := out[stopIdx-zcnt:]
bufsz = len(vBuf)
for idx = 0; idx < bufsz; idx++ {
out[idx] = al[vBuf[idx]]
}
return string(out[:bufsz])
}
// DecodeString takes a base36 encoded string and returns a slice of the decoded
// bytes.
func DecodeString(s string) ([]byte, error) {
if len(s) == 0 {
return nil, fmt.Errorf("can not decode zero-length string")
}
zcnt := 0
for zcnt < len(s) && s[zcnt] == '0' {
zcnt++
}
// the 32bit algo stretches the result up to 2 times
binu := make([]byte, 2*(((len(s))*179/277)+1)) // no more than 84 bytes when len(s) <= 64
outi := make([]uint32, (len(s)+3)/4) // no more than 16 bytes when len(s) <= 64
for _, r := range s {
if r > maxDigitOrdinal || revAlphabet[r] > maxDigitValueB36 {
return nil, fmt.Errorf("invalid base36 character (%q)", r)
}
c := uint64(revAlphabet[r])
for j := len(outi) - 1; j >= 0; j-- {
t := uint64(outi[j])*36 + c
c = (t >> 32)
outi[j] = uint32(t & 0xFFFFFFFF)
}
}
mask := (uint(len(s)%4) * 8)
if mask == 0 {
mask = 32
}
mask -= 8
outidx := 0
for j := 0; j < len(outi); j++ {
for mask < 32 { // loop relies on uint overflow
binu[outidx] = byte(outi[j] >> mask)
mask -= 8
outidx++
}
mask = 24
}
// find the most significant byte post-decode, if any
for msb := zcnt; msb < outidx; msb++ {
if binu[msb] > 0 {
return binu[msb-zcnt : outidx : outidx], nil
}
}
// it's all zeroes
return binu[:outidx:outidx], nil
}

View File

@@ -0,0 +1,3 @@
{
"version": "v0.2.0"
}

View File

@@ -0,0 +1 @@
/madns/madns

View File

@@ -0,0 +1,30 @@
os:
- linux
language: go
go:
- 1.15.x
env:
global:
- GOTFLAGS="-race"
matrix:
- BUILD_DEPTYPE=gomod
# disable travis install
install:
- true
script:
- bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh)
cache:
directories:
- $GOPATH/pkg/mod
- /home/travis/.cache/go-build
notifications:
email: false

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Juan Batiz-Benet
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.

View File

@@ -0,0 +1,57 @@
# go-multiaddr-dns
> Resolve /dns4, /dns6, and /dnsaddr multiaddrs.
```sh
> madns /dnsaddr/ipfs.io/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
/ip6/fc3d:9a4e:3c96:2fd2:1afa:18fe:8dd2:b602/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
/dns4/jupiter.i.ipfs.io/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
/dns6/jupiter.i.ipfs.io/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
```
In more detail:
```sh
> madns /dns6/example.net
/ip6/2001:db8::a3
/ip6/2001:db8::a4
...
> madns /dns4/example.net/tcp/443/wss
/ip4/192.0.2.1/tcp/443/wss
/ip4/192.0.2.2/tcp/443/wss
# No-op if it's not a dns-ish address.
> madns /ip4/127.0.0.1/tcp/8080
/ip4/127.0.0.1/tcp/8080
# /dnsaddr resolves by looking up TXT records.
> dig +short TXT _dnsaddr.example.net
"dnsaddr=/ip6/2001:db8::a3/tcp/443/wss/ipfs/Qmfoo"
"dnsaddr=/ip6/2001:db8::a4/tcp/443/wss/ipfs/Qmbar"
"dnsaddr=/ip4/192.0.2.1/tcp/443/wss/ipfs/Qmfoo"
"dnsaddr=/ip4/192.0.2.2/tcp/443/wss/ipfs/Qmbar"
...
# /dnsaddr returns addrs which encapsulate whatever /dnsaddr encapsulates too.
> madns example.net/ipfs/Qmfoo
info: changing query to /dnsaddr/example.net/ipfs/Qmfoo
/ip6/2001:db8::a3/tcp/443/wss/ipfs/Qmfoo
/ip4/192.0.2.1/tcp/443/wss/ipfs/Qmfoo
# TODO -p filters by protocol stacks.
> madns -p /ip6/tcp/wss /dnsaddr/example.net
/ip6/2001:db8::a3/tcp/443/wss/ipfs/Qmfoo
/ip6/2001:db8::a4/tcp/443/wss/ipfs/Qmbar
# TODO -c filters by CIDR
> madns -c /ip4/104.236.76.0/ipcidr/24 /dnsaddr/example.net
/ip4/192.0.2.2/tcp/443/wss/ipfs/Qmbar
```

29
vendor/github.com/multiformats/go-multiaddr-dns/dns.go generated vendored Normal file
View File

@@ -0,0 +1,29 @@
package madns
import (
ma "github.com/multiformats/go-multiaddr"
)
// Extracted from source of truth for multicodec codes: https://github.com/multiformats/multicodec
const (
// Deprecated: use ma.P_DNS
P_DNS = ma.P_DNS
// Deprecated: use ma.P_DNS4
P_DNS4 = ma.P_DNS4
// Deprecated: use ma.P_DNS6
P_DNS6 = ma.P_DNS6
// Deprecated: use ma.P_DNSADDR
P_DNSADDR = ma.P_DNSADDR
)
// Deprecated: use ma.ProtocolWithCode(P_DNS)
var DnsProtocol = ma.ProtocolWithCode(P_DNS)
// Deprecated: use ma.ProtocolWithCode(P_DNS4)
var Dns4Protocol = ma.ProtocolWithCode(P_DNS4)
// Deprecated: use ma.ProtocolWithCode(P_DNS6)
var Dns6Protocol = ma.ProtocolWithCode(P_DNS6)
// Deprecated: use ma.ProtocolWithCode(P_DNSADDR)
var DnsaddrProtocol = ma.ProtocolWithCode(P_DNSADDR)

View File

@@ -0,0 +1,31 @@
package madns
import (
"context"
"net"
)
type MockResolver struct {
IP map[string][]net.IPAddr
TXT map[string][]string
}
var _ BasicResolver = (*MockResolver)(nil)
func (r *MockResolver) LookupIPAddr(ctx context.Context, name string) ([]net.IPAddr, error) {
results, ok := r.IP[name]
if ok {
return results, nil
} else {
return []net.IPAddr{}, nil
}
}
func (r *MockResolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
results, ok := r.TXT[name]
if ok {
return results, nil
} else {
return []string{}, nil
}
}

View File

@@ -0,0 +1,281 @@
package madns
import (
"context"
"net"
"strings"
"github.com/miekg/dns"
ma "github.com/multiformats/go-multiaddr"
)
var ResolvableProtocols = []ma.Protocol{DnsaddrProtocol, Dns4Protocol, Dns6Protocol, DnsProtocol}
var DefaultResolver = &Resolver{def: net.DefaultResolver}
const dnsaddrTXTPrefix = "dnsaddr="
// BasicResolver is a low level interface for DNS resolution
type BasicResolver interface {
LookupIPAddr(context.Context, string) ([]net.IPAddr, error)
LookupTXT(context.Context, string) ([]string, error)
}
// Resolver is an object capable of resolving dns multiaddrs by using one or more BasicResolvers;
// it supports custom per domain/TLD resolvers.
// It also implements the BasicResolver interface so that it can act as a custom per domain/TLD
// resolver.
type Resolver struct {
def BasicResolver
custom map[string]BasicResolver
}
var _ BasicResolver = (*Resolver)(nil)
// NewResolver creates a new Resolver instance with the specified options
func NewResolver(opts ...Option) (*Resolver, error) {
r := &Resolver{def: net.DefaultResolver}
for _, opt := range opts {
err := opt(r)
if err != nil {
return nil, err
}
}
return r, nil
}
type Option func(*Resolver) error
// WithDefaultResolver is an option that specifies the default basic resolver,
// which resolves any TLD that doesn't have a custom resolver.
// Defaults to net.DefaultResolver
func WithDefaultResolver(def BasicResolver) Option {
return func(r *Resolver) error {
r.def = def
return nil
}
}
// WithDomainResolver specifies a custom resolver for a domain/TLD.
// Custom resolver selection matches domains left to right, with more specific resolvers
// superseding generic ones.
func WithDomainResolver(domain string, rslv BasicResolver) Option {
return func(r *Resolver) error {
if r.custom == nil {
r.custom = make(map[string]BasicResolver)
}
fqdn := dns.Fqdn(domain)
r.custom[fqdn] = rslv
return nil
}
}
func (r *Resolver) getResolver(domain string) BasicResolver {
fqdn := dns.Fqdn(domain)
// we match left-to-right, with more specific resolvers superseding generic ones.
// So for a domain a.b.c, we will try a.b,c, b.c, c, and fallback to the default if
// there is no match
rslv, ok := r.custom[fqdn]
if ok {
return rslv
}
for i := strings.Index(fqdn, "."); i != -1; i = strings.Index(fqdn, ".") {
fqdn = fqdn[i+1:]
if fqdn == "" {
// the . is the default resolver
break
}
rslv, ok = r.custom[fqdn]
if ok {
return rslv
}
}
return r.def
}
// Resolve resolves a DNS multiaddr.
func (r *Resolver) Resolve(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) {
var results []ma.Multiaddr
for i := 0; maddr != nil; i++ {
var keep ma.Multiaddr
// Find the next dns component.
keep, maddr = ma.SplitFunc(maddr, func(c ma.Component) bool {
switch c.Protocol().Code {
case DnsProtocol.Code, Dns4Protocol.Code, Dns6Protocol.Code, DnsaddrProtocol.Code:
return true
default:
return false
}
})
// Keep everything before the dns component.
if keep != nil {
if len(results) == 0 {
results = []ma.Multiaddr{keep}
} else {
for i, r := range results {
results[i] = r.Encapsulate(keep)
}
}
}
// If the rest is empty, we've hit the end (there _was_ no dns component).
if maddr == nil {
break
}
// split off the dns component.
var resolve *ma.Component
resolve, maddr = ma.SplitFirst(maddr)
proto := resolve.Protocol()
value := resolve.Value()
rslv := r.getResolver(value)
// resolve the dns component
var resolved []ma.Multiaddr
switch proto.Code {
case Dns4Protocol.Code, Dns6Protocol.Code, DnsProtocol.Code:
// The dns, dns4, and dns6 resolver simply resolves each
// dns* component into an ipv4/ipv6 address.
v4only := proto.Code == Dns4Protocol.Code
v6only := proto.Code == Dns6Protocol.Code
// XXX: Unfortunately, go does a pretty terrible job of
// differentiating between IPv6 and IPv4. A v4-in-v6
// AAAA record will _look_ like an A record to us and
// there's nothing we can do about that.
records, err := rslv.LookupIPAddr(ctx, value)
if err != nil {
return nil, err
}
// Convert each DNS record into a multiaddr. If the
// protocol is dns4, throw away any IPv6 addresses. If
// the protocol is dns6, throw away any IPv4 addresses.
for _, r := range records {
var (
rmaddr ma.Multiaddr
err error
)
ip4 := r.IP.To4()
if ip4 == nil {
if v4only {
continue
}
rmaddr, err = ma.NewMultiaddr("/ip6/" + r.IP.String())
} else {
if v6only {
continue
}
rmaddr, err = ma.NewMultiaddr("/ip4/" + ip4.String())
}
if err != nil {
return nil, err
}
resolved = append(resolved, rmaddr)
}
case DnsaddrProtocol.Code:
// The dnsaddr resolver is a bit more complicated. We:
//
// 1. Lookup the dnsaddr txt record on _dnsaddr.DOMAIN.TLD
// 2. Take everything _after_ the `/dnsaddr/DOMAIN.TLD`
// part of the multiaddr.
// 3. Find the dnsaddr records (if any) with suffixes
// matching the result of step 2.
// First, lookup the TXT record
records, err := rslv.LookupTXT(ctx, "_dnsaddr."+value)
if err != nil {
return nil, err
}
// Then, calculate the length of the suffix we're
// looking for.
length := 0
if maddr != nil {
length = addrLen(maddr)
}
for _, r := range records {
// Ignore non dnsaddr TXT records.
if !strings.HasPrefix(r, dnsaddrTXTPrefix) {
continue
}
// Extract and decode the multiaddr.
rmaddr, err := ma.NewMultiaddr(r[len(dnsaddrTXTPrefix):])
if err != nil {
// discard multiaddrs we don't understand.
// XXX: Is this right? It's the best we
// can do for now, really.
continue
}
// If we have a suffix to match on.
if maddr != nil {
// Make sure the new address is at least
// as long as the suffix we're looking
// for.
rmlen := addrLen(rmaddr)
if rmlen < length {
// not long enough.
continue
}
// Matches everything after the /dnsaddr/... with the end of the
// dnsaddr record:
//
// v----------rmlen-----------------v
// /ip4/1.2.3.4/tcp/1234/p2p/QmFoobar
// /p2p/QmFoobar
// ^--(rmlen - length)--^---length--^
if !maddr.Equal(offset(rmaddr, rmlen-length)) {
continue
}
}
resolved = append(resolved, rmaddr)
}
// consumes the rest of the multiaddr as part of the "match" process.
maddr = nil
default:
panic("unreachable")
}
if len(resolved) == 0 {
return nil, nil
} else if len(results) == 0 {
results = resolved
} else {
// We take the cross product here as we don't have any
// better way to represent "ORs" in multiaddrs. For
// example, `/dns/foo.com/p2p-circuit/dns/bar.com` could
// resolve to:
//
// * /ip4/1.1.1.1/p2p-circuit/ip4/2.1.1.1
// * /ip4/1.1.1.1/p2p-circuit/ip4/2.1.1.2
// * /ip4/1.1.1.2/p2p-circuit/ip4/2.1.1.1
// * /ip4/1.1.1.2/p2p-circuit/ip4/2.1.1.2
results = cross(results, resolved)
}
}
return results, nil
}
func (r *Resolver) LookupIPAddr(ctx context.Context, domain string) ([]net.IPAddr, error) {
return r.getResolver(domain).LookupIPAddr(ctx, domain)
}
func (r *Resolver) LookupTXT(ctx context.Context, txt string) ([]string, error) {
return r.getResolver(txt).LookupTXT(ctx, txt)
}

View File

@@ -0,0 +1,57 @@
package madns
import (
"context"
ma "github.com/multiformats/go-multiaddr"
)
func Matches(maddr ma.Multiaddr) (matches bool) {
ma.ForEach(maddr, func(c ma.Component) bool {
switch c.Protocol().Code {
case DnsProtocol.Code, Dns4Protocol.Code, Dns6Protocol.Code, DnsaddrProtocol.Code:
matches = true
}
return !matches
})
return matches
}
func Resolve(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) {
return DefaultResolver.Resolve(ctx, maddr)
}
// counts the number of components in the multiaddr
func addrLen(maddr ma.Multiaddr) int {
length := 0
ma.ForEach(maddr, func(_ ma.Component) bool {
length++
return true
})
return length
}
// trims `offset` components from the beginning of the multiaddr.
func offset(maddr ma.Multiaddr, offset int) ma.Multiaddr {
_, after := ma.SplitFunc(maddr, func(c ma.Component) bool {
if offset == 0 {
return true
}
offset--
return false
})
return after
}
// takes the cross product of two sets of multiaddrs
//
// assumes `a` is non-empty.
func cross(a, b []ma.Multiaddr) []ma.Multiaddr {
res := make([]ma.Multiaddr, 0, len(a)*len(b))
for _, x := range a {
for _, y := range b {
res = append(res, x.Encapsulate(y))
}
}
return res
}

View File

@@ -0,0 +1,31 @@
os:
- linux
language: go
go:
- 1.12.x
env:
global:
- GOTFLAGS="-race"
- IPFS_REUSEPORT=false
matrix:
- BUILD_DEPTYPE=gomod
# disable travis install
install:
- true
script:
- bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh)
cache:
directories:
- $GOPATH/pkg/mod
- /home/travis/.cache/go-build
notifications:
email: false

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Jeromy Johnson
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.

View File

@@ -0,0 +1,34 @@
# multiaddr format
A validation checker for multiaddrs. Some basic validators for common address
types are provided, but creating your own combinations is easy.
Usage:
```go
a, _ := ma.NewMultiaddr("/ip4/5.2.67.3/tcp/1708")
TCP.Matches(a) // returns true
```
Making your own validators is easy, for example, the `Reliable` multiaddr is
defined as follows:
```go
// Define IP as either ipv4 or ipv6
var IP = Or(Base(ma.P_IP4), Base(ma.P_IP6))
// Define TCP as 'tcp' on top of either ipv4 or ipv6
var TCP = And(IP, Base(ma.P_TCP))
// Define UDP as 'udp' on top of either ipv4 or ipv6
var UDP = And(IP, Base(ma.P_UDP))
// Define UTP as 'utp' on top of udp (on top of ipv4 or ipv6)
var UTP = And(UDP, Base(ma.P_UTP))
// Now define a Reliable transport as either tcp or utp
var Reliable = Or(TCP, UTP)
// From here, we can easily define multiaddrs for protocols that can run on top
// of any 'reliable' transport (such as ipfs)
```
NOTE: the above patterns are already implemented in package

View File

@@ -0,0 +1,177 @@
package mafmt
import (
"strings"
ma "github.com/multiformats/go-multiaddr"
)
// Define a dns4 format multiaddr
var DNS4 = Base(ma.P_DNS4)
// Define a dns6 format multiaddr
var DNS6 = Base(ma.P_DNS6)
// Define a dnsaddr, dns, dns4 or dns6 format multiaddr
var DNS = Or(
Base(ma.P_DNS),
Base(ma.P_DNSADDR),
DNS4,
DNS6,
)
// Define IP as either ipv4 or ipv6
var IP = Or(Base(ma.P_IP4), Base(ma.P_IP6))
// Define TCP as 'tcp' on top of either ipv4 or ipv6, or dns equivalents.
var TCP = Or(
And(DNS, Base(ma.P_TCP)),
And(IP, Base(ma.P_TCP)),
)
// Define UDP as 'udp' on top of either ipv4 or ipv6, or dns equivalents.
var UDP = Or(
And(DNS, Base(ma.P_UDP)),
And(IP, Base(ma.P_UDP)),
)
// Define UTP as 'utp' on top of udp (on top of ipv4 or ipv6).
var UTP = And(UDP, Base(ma.P_UTP))
// Define QUIC as 'quic' on top of udp (on top of ipv4 or ipv6)
var QUIC = And(UDP, Base(ma.P_QUIC))
// Define unreliable transport as udp
var Unreliable = Or(UDP)
// Now define a Reliable transport as either tcp or utp or quic
var Reliable = Or(TCP, UTP, QUIC)
// P2P can run over any reliable underlying transport protocol
var P2P = And(Reliable, Base(ma.P_P2P))
// IPFS can run over any reliable underlying transport protocol
//
// Deprecated: use P2P
var IPFS = P2P
// Define http over TCP or DNS or http over DNS format multiaddr
var HTTP = Or(
And(TCP, Base(ma.P_HTTP)),
And(IP, Base(ma.P_HTTP)),
And(DNS, Base(ma.P_HTTP)),
)
// Define https over TCP or DNS or https over DNS format multiaddr
var HTTPS = Or(
And(TCP, Base(ma.P_HTTPS)),
And(IP, Base(ma.P_HTTPS)),
And(DNS, Base(ma.P_HTTPS)),
)
// Define p2p-webrtc-direct over HTTP or p2p-webrtc-direct over HTTPS format multiaddr
var WebRTCDirect = Or(
And(HTTP, Base(ma.P_P2P_WEBRTC_DIRECT)),
And(HTTPS, Base(ma.P_P2P_WEBRTC_DIRECT)))
const (
or = iota
and = iota
)
func And(ps ...Pattern) Pattern {
return &pattern{
Op: and,
Args: ps,
}
}
func Or(ps ...Pattern) Pattern {
return &pattern{
Op: or,
Args: ps,
}
}
type Pattern interface {
Matches(ma.Multiaddr) bool
partialMatch([]ma.Protocol) (bool, []ma.Protocol)
String() string
}
type pattern struct {
Args []Pattern
Op int
}
func (ptrn *pattern) Matches(a ma.Multiaddr) bool {
ok, rem := ptrn.partialMatch(a.Protocols())
return ok && len(rem) == 0
}
func (ptrn *pattern) partialMatch(pcs []ma.Protocol) (bool, []ma.Protocol) {
switch ptrn.Op {
case or:
for _, a := range ptrn.Args {
ok, rem := a.partialMatch(pcs)
if ok {
return true, rem
}
}
return false, nil
case and:
if len(pcs) < len(ptrn.Args) {
return false, nil
}
for i := 0; i < len(ptrn.Args); i++ {
ok, rem := ptrn.Args[i].partialMatch(pcs)
if !ok {
return false, nil
}
pcs = rem
}
return true, pcs
default:
panic("unrecognized pattern operand")
}
}
func (ptrn *pattern) String() string {
var sub []string
for _, a := range ptrn.Args {
sub = append(sub, a.String())
}
switch ptrn.Op {
case and:
return strings.Join(sub, "/")
case or:
return "{" + strings.Join(sub, "|") + "}"
default:
panic("unrecognized pattern op!")
}
}
type Base int
func (p Base) Matches(a ma.Multiaddr) bool {
pcs := a.Protocols()
return pcs[0].Code == int(p) && len(pcs) == 1
}
func (p Base) partialMatch(pcs []ma.Protocol) (bool, []ma.Protocol) {
if len(pcs) == 0 {
return false, nil
}
if pcs[0].Code == int(p) {
return true, pcs[1:]
}
return false, nil
}
func (p Base) String() string {
return ma.ProtocolWithCode(int(p)).Name
}

View File

@@ -0,0 +1,3 @@
.vscode/
multiaddr/multiaddr
tmp/

21
vendor/github.com/multiformats/go-multiaddr/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Juan Batiz-Benet
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.

117
vendor/github.com/multiformats/go-multiaddr/README.md generated vendored Normal file
View File

@@ -0,0 +1,117 @@
# go-multiaddr
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs)
[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
[![GoDoc](https://godoc.org/github.com/multiformats/go-multiaddr?status.svg)](https://godoc.org/github.com/multiformats/go-multiaddr)
[![Travis CI](https://img.shields.io/travis/multiformats/go-multiaddr.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-multiaddr)
[![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-multiaddr.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-multiaddr?branch=master)
> [multiaddr](https://github.com/multiformats/multiaddr) implementation in go
Multiaddr is a standard way to represent addresses that:
- Support any standard network protocols.
- Self-describe (include protocols).
- Have a binary packed format.
- Have a nice string representation.
- Encapsulate well.
## Table of Contents
- [Install](#install)
- [Usage](#usage)
- [Example](#example)
- [Simple](#simple)
- [Protocols](#protocols)
- [En/decapsulate](#endecapsulate)
- [Tunneling](#tunneling)
- [Maintainers](#maintainers)
- [Contribute](#contribute)
- [License](#license)
## Install
```sh
go get github.com/multiformats/go-multiaddr
```
## Usage
### Example
#### Simple
```go
import ma "github.com/multiformats/go-multiaddr"
// construct from a string (err signals parse failure)
m1, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234")
// construct from bytes (err signals parse failure)
m2, err := ma.NewMultiaddrBytes(m1.Bytes())
// true
strings.Equal(m1.String(), "/ip4/127.0.0.1/udp/1234")
strings.Equal(m1.String(), m2.String())
bytes.Equal(m1.Bytes(), m2.Bytes())
m1.Equal(m2)
m2.Equal(m1)
```
#### Protocols
```go
// get the multiaddr protocol description objects
m1.Protocols()
// []Protocol{
// Protocol{ Code: 4, Name: 'ip4', Size: 32},
// Protocol{ Code: 17, Name: 'udp', Size: 16},
// }
```
#### En/decapsulate
```go
import ma "github.com/multiformats/go-multiaddr"
m, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234")
// <Multiaddr /ip4/127.0.0.1/udp/1234>
sctpMA, err := ma.NewMultiaddr("/sctp/5678")
m.Encapsulate(sctpMA)
// <Multiaddr /ip4/127.0.0.1/udp/1234/sctp/5678>
udpMA, err := ma.NewMultiaddr("/udp/1234")
m.Decapsulate(udpMA) // up to + inc last occurrence of subaddr
// <Multiaddr /ip4/127.0.0.1>
```
#### Tunneling
Multiaddr allows expressing tunnels very nicely.
```js
printer, _ := ma.NewMultiaddr("/ip4/192.168.0.13/tcp/80")
proxy, _ := ma.NewMultiaddr("/ip4/10.20.30.40/tcp/443")
printerOverProxy := proxy.Encapsulate(printer)
// /ip4/10.20.30.40/tcp/443/ip4/192.168.0.13/tcp/80
proxyAgain := printerOverProxy.Decapsulate(printer)
// /ip4/10.20.30.40/tcp/443
```
## Contribute
Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multiaddr/issues).
Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
## License
[MIT](LICENSE) © 2014 Juan Batiz-Benet

178
vendor/github.com/multiformats/go-multiaddr/codec.go generated vendored Normal file
View File

@@ -0,0 +1,178 @@
package multiaddr
import (
"bytes"
"fmt"
"strings"
"github.com/multiformats/go-varint"
)
func stringToBytes(s string) ([]byte, error) {
// consume trailing slashes
s = strings.TrimRight(s, "/")
var b bytes.Buffer
sp := strings.Split(s, "/")
if sp[0] != "" {
return nil, fmt.Errorf("failed to parse multiaddr %q: must begin with /", s)
}
// consume first empty elem
sp = sp[1:]
if len(sp) == 0 {
return nil, fmt.Errorf("failed to parse multiaddr %q: empty multiaddr", s)
}
for len(sp) > 0 {
name := sp[0]
p := ProtocolWithName(name)
if p.Code == 0 {
return nil, fmt.Errorf("failed to parse multiaddr %q: unknown protocol %s", s, sp[0])
}
_, _ = b.Write(p.VCode)
sp = sp[1:]
if p.Size == 0 { // no length.
continue
}
if len(sp) < 1 {
return nil, fmt.Errorf("failed to parse multiaddr %q: unexpected end of multiaddr", s)
}
if p.Path {
// it's a path protocol (terminal).
// consume the rest of the address as the next component.
sp = []string{"/" + strings.Join(sp, "/")}
}
a, err := p.Transcoder.StringToBytes(sp[0])
if err != nil {
return nil, fmt.Errorf("failed to parse multiaddr %q: invalid value %q for protocol %s: %s", s, sp[0], p.Name, err)
}
if p.Size < 0 { // varint size.
_, _ = b.Write(varint.ToUvarint(uint64(len(a))))
}
b.Write(a)
sp = sp[1:]
}
return b.Bytes(), nil
}
func validateBytes(b []byte) (err error) {
if len(b) == 0 {
return fmt.Errorf("empty multiaddr")
}
for len(b) > 0 {
code, n, err := ReadVarintCode(b)
if err != nil {
return err
}
b = b[n:]
p := ProtocolWithCode(code)
if p.Code == 0 {
return fmt.Errorf("no protocol with code %d", code)
}
if p.Size == 0 {
continue
}
n, size, err := sizeForAddr(p, b)
if err != nil {
return err
}
b = b[n:]
if len(b) < size || size < 0 {
return fmt.Errorf("invalid value for size %d", len(b))
}
err = p.Transcoder.ValidateBytes(b[:size])
if err != nil {
return err
}
b = b[size:]
}
return nil
}
func readComponent(b []byte) (int, Component, error) {
var offset int
code, n, err := ReadVarintCode(b)
if err != nil {
return 0, Component{}, err
}
offset += n
p := ProtocolWithCode(code)
if p.Code == 0 {
return 0, Component{}, fmt.Errorf("no protocol with code %d", code)
}
if p.Size == 0 {
return offset, Component{
bytes: b[:offset],
offset: offset,
protocol: p,
}, nil
}
n, size, err := sizeForAddr(p, b[offset:])
if err != nil {
return 0, Component{}, err
}
offset += n
if len(b[offset:]) < size || size < 0 {
return 0, Component{}, fmt.Errorf("invalid value for size %d", len(b[offset:]))
}
return offset + size, Component{
bytes: b[:offset+size],
protocol: p,
offset: offset,
}, nil
}
func bytesToString(b []byte) (ret string, err error) {
if len(b) == 0 {
return "", fmt.Errorf("empty multiaddr")
}
var buf strings.Builder
for len(b) > 0 {
n, c, err := readComponent(b)
if err != nil {
return "", err
}
b = b[n:]
c.writeTo(&buf)
}
return buf.String(), nil
}
func sizeForAddr(p Protocol, b []byte) (skip, size int, err error) {
switch {
case p.Size > 0:
return 0, (p.Size / 8), nil
case p.Size == 0:
return 0, 0, nil
default:
size, n, err := ReadVarintCode(b)
if err != nil {
return 0, 0, err
}
return n, size, nil
}
}

View File

@@ -0,0 +1,2 @@
ignore:
- "multiaddr"

View File

@@ -0,0 +1,183 @@
package multiaddr
import (
"bytes"
"encoding/binary"
"encoding/json"
"fmt"
"strings"
"github.com/multiformats/go-varint"
)
// Component is a single multiaddr Component.
type Component struct {
bytes []byte
protocol Protocol
offset int
}
func (c *Component) Bytes() []byte {
return c.bytes
}
func (c *Component) MarshalBinary() ([]byte, error) {
return c.Bytes(), nil
}
func (c *Component) UnmarshalBinary(data []byte) error {
_, comp, err := readComponent(data)
if err != nil {
return err
}
*c = comp
return nil
}
func (c *Component) MarshalText() ([]byte, error) {
return []byte(c.String()), nil
}
func (c *Component) UnmarshalText(data []byte) error {
bytes, err := stringToBytes(string(data))
if err != nil {
return err
}
_, comp, err := readComponent(bytes)
if err != nil {
return err
}
*c = comp
return nil
}
func (c *Component) MarshalJSON() ([]byte, error) {
txt, err := c.MarshalText()
if err != nil {
return nil, err
}
return json.Marshal(string(txt))
}
func (m *Component) UnmarshalJSON(data []byte) error {
var v string
if err := json.Unmarshal(data, &v); err != nil {
return err
}
return m.UnmarshalText([]byte(v))
}
func (c *Component) Equal(o Multiaddr) bool {
return bytes.Equal(c.bytes, o.Bytes())
}
func (c *Component) Protocols() []Protocol {
return []Protocol{c.protocol}
}
func (c *Component) Decapsulate(o Multiaddr) Multiaddr {
if c.Equal(o) {
return nil
}
return c
}
func (c *Component) Encapsulate(o Multiaddr) Multiaddr {
m := &multiaddr{bytes: c.bytes}
return m.Encapsulate(o)
}
func (c *Component) ValueForProtocol(code int) (string, error) {
if c.protocol.Code != code {
return "", ErrProtocolNotFound
}
return c.Value(), nil
}
func (c *Component) Protocol() Protocol {
return c.protocol
}
func (c *Component) RawValue() []byte {
return c.bytes[c.offset:]
}
func (c *Component) Value() string {
if c.protocol.Transcoder == nil {
return ""
}
value, err := c.protocol.Transcoder.BytesToString(c.bytes[c.offset:])
if err != nil {
// This Component must have been checked.
panic(err)
}
return value
}
func (c *Component) String() string {
var b strings.Builder
c.writeTo(&b)
return b.String()
}
// writeTo is an efficient, private function for string-formatting a multiaddr.
// Trust me, we tend to allocate a lot when doing this.
func (c *Component) writeTo(b *strings.Builder) {
b.WriteByte('/')
b.WriteString(c.protocol.Name)
value := c.Value()
if len(value) == 0 {
return
}
if !(c.protocol.Path && value[0] == '/') {
b.WriteByte('/')
}
b.WriteString(value)
}
// NewComponent constructs a new multiaddr component
func NewComponent(protocol, value string) (*Component, error) {
p := ProtocolWithName(protocol)
if p.Code == 0 {
return nil, fmt.Errorf("unsupported protocol: %s", protocol)
}
if p.Transcoder != nil {
bts, err := p.Transcoder.StringToBytes(value)
if err != nil {
return nil, err
}
return newComponent(p, bts), nil
} else if value != "" {
return nil, fmt.Errorf("protocol %s doesn't take a value", p.Name)
}
return newComponent(p, nil), nil
// TODO: handle path /?
}
func newComponent(protocol Protocol, bvalue []byte) *Component {
size := len(bvalue)
size += len(protocol.VCode)
if protocol.Size < 0 {
size += varint.UvarintSize(uint64(len(bvalue)))
}
maddr := make([]byte, size)
var offset int
offset += copy(maddr[offset:], protocol.VCode)
if protocol.Size < 0 {
offset += binary.PutUvarint(maddr[offset:], uint64(len(bvalue)))
}
copy(maddr[offset:], bvalue)
// For debugging
if len(maddr) != offset+len(bvalue) {
panic("incorrect length")
}
return &Component{
bytes: maddr,
protocol: protocol,
offset: offset,
}
}

35
vendor/github.com/multiformats/go-multiaddr/doc.go generated vendored Normal file
View File

@@ -0,0 +1,35 @@
/*
Package multiaddr provides an implementation of the Multiaddr network
address format. Multiaddr emphasizes explicitness, self-description, and
portability. It allows applications to treat addresses as opaque tokens,
and to avoid making assumptions about the address representation (e.g. length).
Learn more at https://github.com/multiformats/multiaddr
Basic Use:
import (
"bytes"
"strings"
ma "github.com/multiformats/go-multiaddr"
)
// construct from a string (err signals parse failure)
m1, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234")
// construct from bytes (err signals parse failure)
m2, err := ma.NewMultiaddrBytes(m1.Bytes())
// true
strings.Equal(m1.String(), "/ip4/127.0.0.1/udp/1234")
strings.Equal(m1.String(), m2.String())
bytes.Equal(m1.Bytes(), m2.Bytes())
m1.Equal(m2)
m2.Equal(m1)
// tunneling (en/decap)
printer, _ := ma.NewMultiaddr("/ip4/192.168.0.13/tcp/80")
proxy, _ := ma.NewMultiaddr("/ip4/10.20.30.40/tcp/443")
printerOverProxy := proxy.Encapsulate(printer)
proxyAgain := printerOverProxy.Decapsulate(printer)
*/
package multiaddr

145
vendor/github.com/multiformats/go-multiaddr/filter.go generated vendored Normal file
View File

@@ -0,0 +1,145 @@
package multiaddr
import (
"net"
"sync"
)
// Action is an enum modelling all possible filter actions.
type Action int32
const (
ActionNone Action = iota // zero value.
ActionAccept
ActionDeny
)
type filterEntry struct {
f net.IPNet
action Action
}
// Filters is a structure representing a collection of accept/deny
// net.IPNet filters, together with the DefaultAction flag, which
// represents the default filter policy.
//
// Note that the last policy added to the Filters is authoritative.
type Filters struct {
DefaultAction Action
mu sync.RWMutex
filters []*filterEntry
}
// NewFilters constructs and returns a new set of net.IPNet filters.
// By default, the new filter accepts all addresses.
func NewFilters() *Filters {
return &Filters{
DefaultAction: ActionAccept,
filters: make([]*filterEntry, 0),
}
}
func (fs *Filters) find(ipnet net.IPNet) (int, *filterEntry) {
s := ipnet.String()
for idx, ft := range fs.filters {
if ft.f.String() == s {
return idx, ft
}
}
return -1, nil
}
// AddFilter adds a rule to the Filters set, enforcing the desired action for
// the provided IPNet mask.
func (fs *Filters) AddFilter(ipnet net.IPNet, action Action) {
fs.mu.Lock()
defer fs.mu.Unlock()
if _, f := fs.find(ipnet); f != nil {
f.action = action
} else {
fs.filters = append(fs.filters, &filterEntry{ipnet, action})
}
}
// RemoveLiteral removes the first filter associated with the supplied IPNet,
// returning whether something was removed or not. It makes no distinction
// between whether the rule is an accept or a deny.
func (fs *Filters) RemoveLiteral(ipnet net.IPNet) (removed bool) {
fs.mu.Lock()
defer fs.mu.Unlock()
if idx, _ := fs.find(ipnet); idx != -1 {
fs.filters = append(fs.filters[:idx], fs.filters[idx+1:]...)
return true
}
return false
}
// AddrBlocked parses a ma.Multiaddr and, if a valid netip is found, it applies the
// Filter set rules, returning true if the given address should be denied, and false if
// the given address is accepted.
//
// If a parsing error occurs, or no filter matches, the Filters'
// default is returned.
//
// TODO: currently, the last filter to match wins always, but it shouldn't be that way.
//
// Instead, the highest-specific last filter should win; that way more specific filters
// override more general ones.
func (fs *Filters) AddrBlocked(a Multiaddr) (deny bool) {
var (
netip net.IP
found bool
)
ForEach(a, func(c Component) bool {
switch c.Protocol().Code {
case P_IP6ZONE:
return true
case P_IP6, P_IP4:
found = true
netip = net.IP(c.RawValue())
return false
default:
return false
}
})
if !found {
return fs.DefaultAction == ActionDeny
}
fs.mu.RLock()
defer fs.mu.RUnlock()
action := fs.DefaultAction
for _, ft := range fs.filters {
if ft.f.Contains(netip) {
action = ft.action
}
}
return action == ActionDeny
}
func (fs *Filters) ActionForFilter(ipnet net.IPNet) (action Action, ok bool) {
if _, f := fs.find(ipnet); f != nil {
return f.action, true
}
return ActionNone, false
}
// FiltersForAction returns the filters associated with the indicated action.
func (fs *Filters) FiltersForAction(action Action) (result []net.IPNet) {
fs.mu.RLock()
defer fs.mu.RUnlock()
for _, ff := range fs.filters {
if ff.action == action {
result = append(result, ff.f)
}
}
return result
}

View File

@@ -0,0 +1,63 @@
package multiaddr
import (
"encoding"
"encoding/json"
)
/*
Multiaddr is a cross-protocol, cross-platform format for representing
internet addresses. It emphasizes explicitness and self-description.
Learn more here: https://github.com/multiformats/multiaddr
Multiaddrs have both a binary and string representation.
import ma "github.com/multiformats/go-multiaddr"
addr, err := ma.NewMultiaddr("/ip4/1.2.3.4/tcp/80")
// err non-nil when parsing failed.
*/
type Multiaddr interface {
json.Marshaler
json.Unmarshaler
encoding.TextMarshaler
encoding.TextUnmarshaler
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
// Equal returns whether two Multiaddrs are exactly equal
Equal(Multiaddr) bool
// Bytes returns the []byte representation of this Multiaddr
//
// This function may expose immutable, internal state. Do not modify.
Bytes() []byte
// String returns the string representation of this Multiaddr
// (may panic if internal state is corrupted)
String() string
// Protocols returns the list of Protocols this Multiaddr includes
// will panic if protocol code incorrect (and bytes accessed incorrectly)
Protocols() []Protocol
// Encapsulate wraps this Multiaddr around another. For example:
//
// /ip4/1.2.3.4 encapsulate /tcp/80 = /ip4/1.2.3.4/tcp/80
//
Encapsulate(Multiaddr) Multiaddr
// Decapsulate removes a Multiaddr wrapping. For example:
//
// /ip4/1.2.3.4/tcp/80 decapsulate /tcp/80 = /ip4/1.2.3.4
// /ip4/1.2.3.4/tcp/80 decapsulate /udp/80 = /ip4/1.2.3.4/tcp/80
// /ip4/1.2.3.4/tcp/80 decapsulate /ip4/1.2.3.4 = nil
//
Decapsulate(Multiaddr) Multiaddr
// ValueForProtocol returns the value (if any) following the specified protocol
//
// Note: protocols can appear multiple times in a single multiaddr.
// Consider using `ForEach` to walk over the addr manually.
ValueForProtocol(code int) (string, error)
}

View File

@@ -0,0 +1,235 @@
package multiaddr
import (
"bytes"
"encoding/json"
"fmt"
"log"
"strings"
"golang.org/x/exp/slices"
)
// multiaddr is the data structure representing a Multiaddr
type multiaddr struct {
bytes []byte
}
// NewMultiaddr parses and validates an input string, returning a *Multiaddr
func NewMultiaddr(s string) (a Multiaddr, err error) {
defer func() {
if e := recover(); e != nil {
log.Printf("Panic in NewMultiaddr on input %q: %s", s, e)
err = fmt.Errorf("%v", e)
}
}()
b, err := stringToBytes(s)
if err != nil {
return nil, err
}
return &multiaddr{bytes: b}, nil
}
// NewMultiaddrBytes initializes a Multiaddr from a byte representation.
// It validates it as an input string.
func NewMultiaddrBytes(b []byte) (a Multiaddr, err error) {
defer func() {
if e := recover(); e != nil {
log.Printf("Panic in NewMultiaddrBytes on input %q: %s", b, e)
err = fmt.Errorf("%v", e)
}
}()
if err := validateBytes(b); err != nil {
return nil, err
}
return &multiaddr{bytes: b}, nil
}
// Equal tests whether two multiaddrs are equal
func (m *multiaddr) Equal(m2 Multiaddr) bool {
return bytes.Equal(m.bytes, m2.Bytes())
}
// Bytes returns the []byte representation of this Multiaddr
//
// Do not modify the returned buffer, it may be shared.
func (m *multiaddr) Bytes() []byte {
return m.bytes
}
// String returns the string representation of a Multiaddr
func (m *multiaddr) String() string {
s, err := bytesToString(m.bytes)
if err != nil {
panic(fmt.Errorf("multiaddr failed to convert back to string. corrupted? %s", err))
}
return s
}
func (m *multiaddr) MarshalBinary() ([]byte, error) {
return m.Bytes(), nil
}
func (m *multiaddr) UnmarshalBinary(data []byte) error {
new, err := NewMultiaddrBytes(data)
if err != nil {
return err
}
*m = *(new.(*multiaddr))
return nil
}
func (m *multiaddr) MarshalText() ([]byte, error) {
return []byte(m.String()), nil
}
func (m *multiaddr) UnmarshalText(data []byte) error {
new, err := NewMultiaddr(string(data))
if err != nil {
return err
}
*m = *(new.(*multiaddr))
return nil
}
func (m *multiaddr) MarshalJSON() ([]byte, error) {
return json.Marshal(m.String())
}
func (m *multiaddr) UnmarshalJSON(data []byte) error {
var v string
if err := json.Unmarshal(data, &v); err != nil {
return err
}
new, err := NewMultiaddr(v)
*m = *(new.(*multiaddr))
return err
}
// Protocols returns the list of protocols this Multiaddr has.
// will panic in case we access bytes incorrectly.
func (m *multiaddr) Protocols() []Protocol {
ps := make([]Protocol, 0, 8)
b := m.bytes
for len(b) > 0 {
code, n, err := ReadVarintCode(b)
if err != nil {
panic(err)
}
p := ProtocolWithCode(code)
if p.Code == 0 {
// this is a panic (and not returning err) because this should've been
// caught on constructing the Multiaddr
panic(fmt.Errorf("no protocol with code %d", b[0]))
}
ps = append(ps, p)
b = b[n:]
n, size, err := sizeForAddr(p, b)
if err != nil {
panic(err)
}
b = b[n+size:]
}
return ps
}
// Encapsulate wraps a given Multiaddr, returning the resulting joined Multiaddr
func (m *multiaddr) Encapsulate(o Multiaddr) Multiaddr {
mb := m.bytes
ob := o.Bytes()
b := make([]byte, len(mb)+len(ob))
copy(b, mb)
copy(b[len(mb):], ob)
return &multiaddr{bytes: b}
}
// Decapsulate unwraps Multiaddr up until the given Multiaddr is found.
func (m *multiaddr) Decapsulate(o Multiaddr) Multiaddr {
s1 := m.String()
s2 := o.String()
i := strings.LastIndex(s1, s2)
if i < 0 {
// if multiaddr not contained, returns a copy.
cpy := make([]byte, len(m.bytes))
copy(cpy, m.bytes)
return &multiaddr{bytes: cpy}
}
if i == 0 {
return nil
}
ma, err := NewMultiaddr(s1[:i])
if err != nil {
panic("Multiaddr.Decapsulate incorrect byte boundaries.")
}
return ma
}
var ErrProtocolNotFound = fmt.Errorf("protocol not found in multiaddr")
func (m *multiaddr) ValueForProtocol(code int) (value string, err error) {
err = ErrProtocolNotFound
ForEach(m, func(c Component) bool {
if c.Protocol().Code == code {
value = c.Value()
err = nil
return false
}
return true
})
return
}
// FilterAddrs is a filter that removes certain addresses, according to the given filters.
// If all filters return true, the address is kept.
func FilterAddrs(a []Multiaddr, filters ...func(Multiaddr) bool) []Multiaddr {
b := make([]Multiaddr, 0, len(a))
addrloop:
for _, addr := range a {
for _, filter := range filters {
if !filter(addr) {
continue addrloop
}
}
b = append(b, addr)
}
return b
}
// Contains reports whether addr is contained in addrs.
func Contains(addrs []Multiaddr, addr Multiaddr) bool {
for _, a := range addrs {
if addr.Equal(a) {
return true
}
}
return false
}
// Unique deduplicates addresses in place, leave only unique addresses.
// It doesn't allocate.
func Unique(addrs []Multiaddr) []Multiaddr {
if len(addrs) == 0 {
return addrs
}
// Use the new slices package here, as the sort function doesn't allocate (sort.Slice does).
slices.SortFunc(addrs, func(a, b Multiaddr) int { return bytes.Compare(a.Bytes(), b.Bytes()) })
idx := 1
for i := 1; i < len(addrs); i++ {
if !addrs[i-1].Equal(addrs[i]) {
addrs[idx] = addrs[i]
idx++
}
}
for i := idx; i < len(addrs); i++ {
addrs[i] = nil
}
return addrs[:idx]
}

View File

@@ -0,0 +1,358 @@
package manet
import (
"errors"
"fmt"
"net"
"path/filepath"
"runtime"
"strings"
ma "github.com/multiformats/go-multiaddr"
)
var errIncorrectNetAddr = fmt.Errorf("incorrect network addr conversion")
var errNotIP = fmt.Errorf("multiaddr does not start with an IP address")
// FromNetAddr converts a net.Addr type to a Multiaddr.
func FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
return defaultCodecs.FromNetAddr(a)
}
// FromNetAddr converts a net.Addr to Multiaddress.
func (cm *CodecMap) FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
if a == nil {
return nil, fmt.Errorf("nil multiaddr")
}
p, err := cm.getAddrParser(a.Network())
if err != nil {
return nil, err
}
return p(a)
}
// ToNetAddr converts a Multiaddr to a net.Addr
// Must be ThinWaist. acceptable protocol stacks are:
// /ip{4,6}/{tcp, udp}
func ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
return defaultCodecs.ToNetAddr(maddr)
}
// ToNetAddr converts a Multiaddress to a standard net.Addr.
func (cm *CodecMap) ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
protos := maddr.Protocols()
final := protos[len(protos)-1]
p, err := cm.getMaddrParser(final.Name)
if err != nil {
return nil, err
}
return p(maddr)
}
// MultiaddrToIPNet converts a multiaddr to an IPNet. Useful for seeing if another IP address is contained within this multiaddr network+mask
func MultiaddrToIPNet(m ma.Multiaddr) (*net.IPNet, error) {
var ipString string
var mask string
ma.ForEach(m, func(c ma.Component) bool {
if c.Protocol().Code == ma.P_IP4 || c.Protocol().Code == ma.P_IP6 {
ipString = c.Value()
}
if c.Protocol().Code == ma.P_IPCIDR {
mask = c.Value()
}
return ipString == "" || mask == ""
})
if ipString == "" {
return nil, errors.New("no ip protocol found")
}
if mask == "" {
return nil, errors.New("no mask found")
}
_, ipnet, err := net.ParseCIDR(ipString + "/" + string(mask))
return ipnet, err
}
func parseBasicNetMaddr(maddr ma.Multiaddr) (net.Addr, error) {
network, host, err := DialArgs(maddr)
if err != nil {
return nil, err
}
switch network {
case "tcp", "tcp4", "tcp6":
return net.ResolveTCPAddr(network, host)
case "udp", "udp4", "udp6":
return net.ResolveUDPAddr(network, host)
case "ip", "ip4", "ip6":
return net.ResolveIPAddr(network, host)
case "unix":
return net.ResolveUnixAddr(network, host)
}
return nil, fmt.Errorf("network not supported: %s", network)
}
func FromIPAndZone(ip net.IP, zone string) (ma.Multiaddr, error) {
switch {
case ip.To4() != nil:
return ma.NewComponent("ip4", ip.String())
case ip.To16() != nil:
ip6, err := ma.NewComponent("ip6", ip.String())
if err != nil {
return nil, err
}
if zone == "" {
return ip6, nil
} else {
zone, err := ma.NewComponent("ip6zone", zone)
if err != nil {
return nil, err
}
return zone.Encapsulate(ip6), nil
}
default:
return nil, errIncorrectNetAddr
}
}
// FromIP converts a net.IP type to a Multiaddr.
func FromIP(ip net.IP) (ma.Multiaddr, error) {
return FromIPAndZone(ip, "")
}
// ToIP converts a Multiaddr to a net.IP when possible
func ToIP(addr ma.Multiaddr) (net.IP, error) {
var ip net.IP
ma.ForEach(addr, func(c ma.Component) bool {
switch c.Protocol().Code {
case ma.P_IP6ZONE:
// we can't return these anyways.
return true
case ma.P_IP6, ma.P_IP4:
ip = net.IP(c.RawValue())
return false
}
return false
})
if ip == nil {
return nil, errNotIP
}
return ip, nil
}
// DialArgs is a convenience function that returns network and address as
// expected by net.Dial. See https://godoc.org/net#Dial for an overview of
// possible return values (we do not support the unixpacket ones yet). Unix
// addresses do not, at present, compose.
func DialArgs(m ma.Multiaddr) (string, string, error) {
zone, network, ip, port, hostname, err := dialArgComponents(m)
if err != nil {
return "", "", err
}
// If we have a hostname (dns*), we don't want any fancy ipv6 formatting
// logic (zone, brackets, etc.).
if hostname {
switch network {
case "ip", "ip4", "ip6":
return network, ip, nil
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
return network, ip + ":" + port, nil
}
// Hostname is only true when network is one of the above.
panic("unreachable")
}
switch network {
case "ip6":
if zone != "" {
ip += "%" + zone
}
fallthrough
case "ip4":
return network, ip, nil
case "tcp4", "udp4":
return network, ip + ":" + port, nil
case "tcp6", "udp6":
if zone != "" {
ip += "%" + zone
}
return network, "[" + ip + "]" + ":" + port, nil
case "unix":
if runtime.GOOS == "windows" {
// convert /c:/... to c:\...
ip = filepath.FromSlash(strings.TrimLeft(ip, "/"))
}
return network, ip, nil
default:
return "", "", fmt.Errorf("%s is not a 'thin waist' address", m)
}
}
// dialArgComponents extracts the raw pieces used in dialing a Multiaddr
func dialArgComponents(m ma.Multiaddr) (zone, network, ip, port string, hostname bool, err error) {
ma.ForEach(m, func(c ma.Component) bool {
switch network {
case "":
switch c.Protocol().Code {
case ma.P_IP6ZONE:
if zone != "" {
err = fmt.Errorf("%s has multiple zones", m)
return false
}
zone = c.Value()
return true
case ma.P_IP6:
network = "ip6"
ip = c.Value()
return true
case ma.P_IP4:
if zone != "" {
err = fmt.Errorf("%s has ip4 with zone", m)
return false
}
network = "ip4"
ip = c.Value()
return true
case ma.P_DNS:
network = "ip"
hostname = true
ip = c.Value()
return true
case ma.P_DNS4:
network = "ip4"
hostname = true
ip = c.Value()
return true
case ma.P_DNS6:
network = "ip6"
hostname = true
ip = c.Value()
return true
case ma.P_UNIX:
network = "unix"
ip = c.Value()
return false
}
case "ip":
switch c.Protocol().Code {
case ma.P_UDP:
network = "udp"
case ma.P_TCP:
network = "tcp"
default:
return false
}
port = c.Value()
case "ip4":
switch c.Protocol().Code {
case ma.P_UDP:
network = "udp4"
case ma.P_TCP:
network = "tcp4"
default:
return false
}
port = c.Value()
case "ip6":
switch c.Protocol().Code {
case ma.P_UDP:
network = "udp6"
case ma.P_TCP:
network = "tcp6"
default:
return false
}
port = c.Value()
}
// Done.
return false
})
return
}
func parseTCPNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.TCPAddr)
if !ok {
return nil, errIncorrectNetAddr
}
// Get IP Addr
ipm, err := FromIPAndZone(ac.IP, ac.Zone)
if err != nil {
return nil, errIncorrectNetAddr
}
// Get TCP Addr
tcpm, err := ma.NewMultiaddr(fmt.Sprintf("/tcp/%d", ac.Port))
if err != nil {
return nil, errIncorrectNetAddr
}
// Encapsulate
return ipm.Encapsulate(tcpm), nil
}
func parseUDPNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.UDPAddr)
if !ok {
return nil, errIncorrectNetAddr
}
// Get IP Addr
ipm, err := FromIPAndZone(ac.IP, ac.Zone)
if err != nil {
return nil, errIncorrectNetAddr
}
// Get UDP Addr
udpm, err := ma.NewMultiaddr(fmt.Sprintf("/udp/%d", ac.Port))
if err != nil {
return nil, errIncorrectNetAddr
}
// Encapsulate
return ipm.Encapsulate(udpm), nil
}
func parseIPNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.IPAddr)
if !ok {
return nil, errIncorrectNetAddr
}
return FromIPAndZone(ac.IP, ac.Zone)
}
func parseIPPlusNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.IPNet)
if !ok {
return nil, errIncorrectNetAddr
}
return FromIP(ac.IP)
}
func parseUnixNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.UnixAddr)
if !ok {
return nil, errIncorrectNetAddr
}
path := ac.Name
if runtime.GOOS == "windows" {
// Convert c:\foobar\... to c:/foobar/...
path = filepath.ToSlash(path)
}
if len(path) == 0 || path[0] != '/' {
// convert "" and "c:/..." to "/..."
path = "/" + path
}
return ma.NewComponent("unix", path)
}

View File

@@ -0,0 +1,5 @@
// Package manet provides Multiaddr specific versions of common
// functions in stdlib's net package. This means wrappers of
// standard net symbols like net.Dial and net.Listen, as well
// as conversion to/from net.Addr.
package manet

136
vendor/github.com/multiformats/go-multiaddr/net/ip.go generated vendored Normal file
View File

@@ -0,0 +1,136 @@
package manet
import (
"net"
ma "github.com/multiformats/go-multiaddr"
)
// Loopback Addresses
var (
// IP4Loopback is the ip4 loopback multiaddr
IP4Loopback = ma.StringCast("/ip4/127.0.0.1")
// IP6Loopback is the ip6 loopback multiaddr
IP6Loopback = ma.StringCast("/ip6/::1")
// IP4MappedIP6Loopback is the IPv4 Mapped IPv6 loopback address.
IP4MappedIP6Loopback = ma.StringCast("/ip6/::ffff:127.0.0.1")
)
// Unspecified Addresses (used for )
var (
IP4Unspecified = ma.StringCast("/ip4/0.0.0.0")
IP6Unspecified = ma.StringCast("/ip6/::")
)
// IsThinWaist returns whether a Multiaddr starts with "Thin Waist" Protocols.
// This means: /{IP4, IP6}[/{TCP, UDP}]
func IsThinWaist(m ma.Multiaddr) bool {
m = zoneless(m)
if m == nil {
return false
}
p := m.Protocols()
// nothing? not even a waist.
if len(p) == 0 {
return false
}
if p[0].Code != ma.P_IP4 && p[0].Code != ma.P_IP6 {
return false
}
// only IP? still counts.
if len(p) == 1 {
return true
}
switch p[1].Code {
case ma.P_TCP, ma.P_UDP, ma.P_IP4, ma.P_IP6:
return true
default:
return false
}
}
// IsIPLoopback returns whether a Multiaddr starts with a "Loopback" IP address
// This means either /ip4/127.*.*.*/*, /ip6/::1/*, or /ip6/::ffff:127.*.*.*.*/*,
// or /ip6zone/<any value>/ip6/<one of the preceding ip6 values>/*
func IsIPLoopback(m ma.Multiaddr) bool {
m = zoneless(m)
c, _ := ma.SplitFirst(m)
if c == nil {
return false
}
switch c.Protocol().Code {
case ma.P_IP4, ma.P_IP6:
return net.IP(c.RawValue()).IsLoopback()
}
return false
}
// IsIP6LinkLocal returns whether a Multiaddr starts with an IPv6 link-local
// multiaddress (with zero or one leading zone). These addresses are non
// routable.
func IsIP6LinkLocal(m ma.Multiaddr) bool {
m = zoneless(m)
c, _ := ma.SplitFirst(m)
if c == nil || c.Protocol().Code != ma.P_IP6 {
return false
}
ip := net.IP(c.RawValue())
return ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast()
}
// IsIPUnspecified returns whether a Multiaddr starts with an Unspecified IP address
// This means either /ip4/0.0.0.0/* or /ip6/::/*
func IsIPUnspecified(m ma.Multiaddr) bool {
m = zoneless(m)
if m == nil {
return false
}
c, _ := ma.SplitFirst(m)
return net.IP(c.RawValue()).IsUnspecified()
}
// If m matches [zone,ip6,...], return [ip6,...]
// else if m matches [], [zone], or [zone,...], return nil
// else return m
func zoneless(m ma.Multiaddr) ma.Multiaddr {
head, tail := ma.SplitFirst(m)
if head == nil {
return nil
}
if head.Protocol().Code == ma.P_IP6ZONE {
if tail == nil {
return nil
}
tailhead, _ := ma.SplitFirst(tail)
if tailhead.Protocol().Code != ma.P_IP6 {
return nil
}
return tail
} else {
return m
}
}
var nat64WellKnownPrefix net.IPNet
func init() {
_, np, err := net.ParseCIDR("64:ff9b::/96")
if err != nil {
panic(err)
}
nat64WellKnownPrefix = *np
}
// IsNAT64IPv4ConvertedIPv6Addr returns whether addr is a well-known prefix "64:ff9b::/96" addr
// used for NAT64 Translation. See RFC 6052
func IsNAT64IPv4ConvertedIPv6Addr(addr ma.Multiaddr) bool {
c, _ := ma.SplitFirst(addr)
return c != nil && c.Protocol().Code == ma.P_IP6 &&
nat64WellKnownPrefix.Contains(net.IP(c.RawValue()))
}

430
vendor/github.com/multiformats/go-multiaddr/net/net.go generated vendored Normal file
View File

@@ -0,0 +1,430 @@
// Package manet provides Multiaddr
// (https://github.com/multiformats/go-multiaddr) specific versions of common
// functions in Go's standard `net` package. This means wrappers of standard
// net symbols like `net.Dial` and `net.Listen`, as well as conversion to
// and from `net.Addr`.
package manet
import (
"context"
"fmt"
"net"
ma "github.com/multiformats/go-multiaddr"
)
// Conn is the equivalent of a net.Conn object. It is the
// result of calling the Dial or Listen functions in this
// package, with associated local and remote Multiaddrs.
type Conn interface {
net.Conn
// LocalMultiaddr returns the local Multiaddr associated
// with this connection
LocalMultiaddr() ma.Multiaddr
// RemoteMultiaddr returns the remote Multiaddr associated
// with this connection
RemoteMultiaddr() ma.Multiaddr
}
type halfOpen interface {
net.Conn
CloseRead() error
CloseWrite() error
}
func wrap(nconn net.Conn, laddr, raddr ma.Multiaddr) Conn {
endpts := maEndpoints{
laddr: laddr,
raddr: raddr,
}
// This sucks. However, it's the only way to reliably expose the
// underlying methods. This way, users that need access to, e.g.,
// CloseRead and CloseWrite, can do so via type assertions.
switch nconn := nconn.(type) {
case *net.TCPConn:
return &struct {
*net.TCPConn
maEndpoints
}{nconn, endpts}
case *net.UDPConn:
return &struct {
*net.UDPConn
maEndpoints
}{nconn, endpts}
case *net.IPConn:
return &struct {
*net.IPConn
maEndpoints
}{nconn, endpts}
case *net.UnixConn:
return &struct {
*net.UnixConn
maEndpoints
}{nconn, endpts}
case halfOpen:
return &struct {
halfOpen
maEndpoints
}{nconn, endpts}
default:
return &struct {
net.Conn
maEndpoints
}{nconn, endpts}
}
}
// WrapNetConn wraps a net.Conn object with a Multiaddr friendly Conn.
//
// This function does it's best to avoid "hiding" methods exposed by the wrapped
// type. Guarantees:
//
// - If the wrapped connection exposes the "half-open" closer methods
// (CloseWrite, CloseRead), these will be available on the wrapped connection
// via type assertions.
// - If the wrapped connection is a UnixConn, IPConn, TCPConn, or UDPConn, all
// methods on these wrapped connections will be available via type assertions.
func WrapNetConn(nconn net.Conn) (Conn, error) {
if nconn == nil {
return nil, fmt.Errorf("failed to convert nconn.LocalAddr: nil")
}
laddr, err := FromNetAddr(nconn.LocalAddr())
if err != nil {
return nil, fmt.Errorf("failed to convert nconn.LocalAddr: %s", err)
}
raddr, err := FromNetAddr(nconn.RemoteAddr())
if err != nil {
return nil, fmt.Errorf("failed to convert nconn.RemoteAddr: %s", err)
}
return wrap(nconn, laddr, raddr), nil
}
type maEndpoints struct {
laddr ma.Multiaddr
raddr ma.Multiaddr
}
// LocalMultiaddr returns the local address associated with
// this connection
func (c *maEndpoints) LocalMultiaddr() ma.Multiaddr {
return c.laddr
}
// RemoteMultiaddr returns the remote address associated with
// this connection
func (c *maEndpoints) RemoteMultiaddr() ma.Multiaddr {
return c.raddr
}
// Dialer contains options for connecting to an address. It
// is effectively the same as net.Dialer, but its LocalAddr
// and RemoteAddr options are Multiaddrs, instead of net.Addrs.
type Dialer struct {
// Dialer is just an embedded net.Dialer, with all its options.
net.Dialer
// LocalAddr is the local address to use when dialing an
// address. The address must be of a compatible type for the
// network being dialed.
// If nil, a local address is automatically chosen.
LocalAddr ma.Multiaddr
}
// Dial connects to a remote address, using the options of the
// Dialer. Dialer uses an underlying net.Dialer to Dial a
// net.Conn, then wraps that in a Conn object (with local and
// remote Multiaddrs).
func (d *Dialer) Dial(remote ma.Multiaddr) (Conn, error) {
return d.DialContext(context.Background(), remote)
}
// DialContext allows to provide a custom context to Dial().
func (d *Dialer) DialContext(ctx context.Context, remote ma.Multiaddr) (Conn, error) {
// if a LocalAddr is specified, use it on the embedded dialer.
if d.LocalAddr != nil {
// convert our multiaddr to net.Addr friendly
naddr, err := ToNetAddr(d.LocalAddr)
if err != nil {
return nil, err
}
// set the dialer's LocalAddr as naddr
d.Dialer.LocalAddr = naddr
}
// get the net.Dial friendly arguments from the remote addr
rnet, rnaddr, err := DialArgs(remote)
if err != nil {
return nil, err
}
// ok, Dial!
var nconn net.Conn
switch rnet {
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "unix":
nconn, err = d.Dialer.DialContext(ctx, rnet, rnaddr)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unrecognized network: %s", rnet)
}
// get local address (pre-specified or assigned within net.Conn)
local := d.LocalAddr
// This block helps us avoid parsing addresses in transports (such as unix
// sockets) that don't have local addresses when dialing out.
if local == nil && nconn.LocalAddr().String() != "" {
local, err = FromNetAddr(nconn.LocalAddr())
if err != nil {
return nil, err
}
}
return wrap(nconn, local, remote), nil
}
// Dial connects to a remote address. It uses an underlying net.Conn,
// then wraps it in a Conn object (with local and remote Multiaddrs).
func Dial(remote ma.Multiaddr) (Conn, error) {
return (&Dialer{}).Dial(remote)
}
// A Listener is a generic network listener for stream-oriented protocols.
// it uses an embedded net.Listener, overriding net.Listener.Accept to
// return a Conn and providing Multiaddr.
type Listener interface {
// Accept waits for and returns the next connection to the listener.
// Returns a Multiaddr friendly Conn
Accept() (Conn, error)
// Close closes the listener.
// Any blocked Accept operations will be unblocked and return errors.
Close() error
// Multiaddr returns the listener's (local) Multiaddr.
Multiaddr() ma.Multiaddr
// Addr returns the net.Listener's network address.
Addr() net.Addr
}
type netListenerAdapter struct {
Listener
}
func (nla *netListenerAdapter) Accept() (net.Conn, error) {
return nla.Listener.Accept()
}
// NetListener turns this Listener into a net.Listener.
//
// - Connections returned from Accept implement multiaddr/net Conn.
// - Calling WrapNetListener on the net.Listener returned by this function will
// return the original (underlying) multiaddr/net Listener.
func NetListener(l Listener) net.Listener {
return &netListenerAdapter{l}
}
// maListener implements Listener
type maListener struct {
net.Listener
laddr ma.Multiaddr
}
// Accept waits for and returns the next connection to the listener.
// Returns a Multiaddr friendly Conn
func (l *maListener) Accept() (Conn, error) {
nconn, err := l.Listener.Accept()
if err != nil {
return nil, err
}
var raddr ma.Multiaddr
// This block protects us in transports (i.e. unix sockets) that don't have
// remote addresses for inbound connections.
if addr := nconn.RemoteAddr(); addr != nil && addr.String() != "" {
raddr, err = FromNetAddr(addr)
if err != nil {
return nil, fmt.Errorf("failed to convert conn.RemoteAddr: %s", err)
}
}
var laddr ma.Multiaddr
if addr := nconn.LocalAddr(); addr != nil && addr.String() != "" {
laddr, err = FromNetAddr(addr)
if err != nil {
return nil, fmt.Errorf("failed to convert conn.LocalAddr: %s", err)
}
}
return wrap(nconn, laddr, raddr), nil
}
// Multiaddr returns the listener's (local) Multiaddr.
func (l *maListener) Multiaddr() ma.Multiaddr {
return l.laddr
}
// Addr returns the listener's network address.
func (l *maListener) Addr() net.Addr {
return l.Listener.Addr()
}
// Listen announces on the local network address laddr.
// The Multiaddr must be a "ThinWaist" stream-oriented network:
// ip4/tcp, ip6/tcp, (TODO: unix, unixpacket)
// See Dial for the syntax of laddr.
func Listen(laddr ma.Multiaddr) (Listener, error) {
// get the net.Listen friendly arguments from the remote addr
lnet, lnaddr, err := DialArgs(laddr)
if err != nil {
return nil, err
}
nl, err := net.Listen(lnet, lnaddr)
if err != nil {
return nil, err
}
// we want to fetch the new multiaddr from the listener, as it may
// have resolved to some other value. WrapNetListener does it for us.
return WrapNetListener(nl)
}
// WrapNetListener wraps a net.Listener with a manet.Listener.
func WrapNetListener(nl net.Listener) (Listener, error) {
if nla, ok := nl.(*netListenerAdapter); ok {
return nla.Listener, nil
}
laddr, err := FromNetAddr(nl.Addr())
if err != nil {
return nil, err
}
return &maListener{
Listener: nl,
laddr: laddr,
}, nil
}
// A PacketConn is a generic packet oriented network connection which uses an
// underlying net.PacketConn, wrapped with the locally bound Multiaddr.
type PacketConn interface {
net.PacketConn
LocalMultiaddr() ma.Multiaddr
ReadFromMultiaddr(b []byte) (int, ma.Multiaddr, error)
WriteToMultiaddr(b []byte, maddr ma.Multiaddr) (int, error)
}
// maPacketConn implements PacketConn
type maPacketConn struct {
net.PacketConn
laddr ma.Multiaddr
}
var _ PacketConn = (*maPacketConn)(nil)
// LocalMultiaddr returns the bound local Multiaddr.
func (l *maPacketConn) LocalMultiaddr() ma.Multiaddr {
return l.laddr
}
func (l *maPacketConn) ReadFromMultiaddr(b []byte) (int, ma.Multiaddr, error) {
n, addr, err := l.ReadFrom(b)
maddr, _ := FromNetAddr(addr)
return n, maddr, err
}
func (l *maPacketConn) WriteToMultiaddr(b []byte, maddr ma.Multiaddr) (int, error) {
addr, err := ToNetAddr(maddr)
if err != nil {
return 0, err
}
return l.WriteTo(b, addr)
}
// ListenPacket announces on the local network address laddr.
// The Multiaddr must be a packet driven network, like udp4 or udp6.
// See Dial for the syntax of laddr.
func ListenPacket(laddr ma.Multiaddr) (PacketConn, error) {
lnet, lnaddr, err := DialArgs(laddr)
if err != nil {
return nil, err
}
pc, err := net.ListenPacket(lnet, lnaddr)
if err != nil {
return nil, err
}
// We want to fetch the new multiaddr from the listener, as it may
// have resolved to some other value. WrapPacketConn does this.
return WrapPacketConn(pc)
}
// WrapPacketConn wraps a net.PacketConn with a manet.PacketConn.
func WrapPacketConn(pc net.PacketConn) (PacketConn, error) {
laddr, err := FromNetAddr(pc.LocalAddr())
if err != nil {
return nil, err
}
return &maPacketConn{
PacketConn: pc,
laddr: laddr,
}, nil
}
// InterfaceMultiaddrs will return the addresses matching net.InterfaceAddrs
func InterfaceMultiaddrs() ([]ma.Multiaddr, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return nil, err
}
maddrs := make([]ma.Multiaddr, len(addrs))
for i, a := range addrs {
maddrs[i], err = FromNetAddr(a)
if err != nil {
return nil, err
}
}
return maddrs, nil
}
// AddrMatch returns the Multiaddrs that match the protocol stack on addr
func AddrMatch(match ma.Multiaddr, addrs []ma.Multiaddr) []ma.Multiaddr {
// we should match transports entirely.
p1s := match.Protocols()
out := make([]ma.Multiaddr, 0, len(addrs))
for _, a := range addrs {
p2s := a.Protocols()
if len(p1s) != len(p2s) {
continue
}
match := true
for i, p2 := range p2s {
if p1s[i].Code != p2.Code {
match = false
break
}
}
if match {
out = append(out, a)
}
}
return out
}

View File

@@ -0,0 +1,177 @@
package manet
import (
"net"
"strings"
ma "github.com/multiformats/go-multiaddr"
)
// Private4 and Private6 are well-known private networks
var Private4, Private6 []*net.IPNet
var privateCIDR4 = []string{
// localhost
"127.0.0.0/8",
// private networks
"10.0.0.0/8",
"100.64.0.0/10",
"172.16.0.0/12",
"192.168.0.0/16",
// link local
"169.254.0.0/16",
}
var privateCIDR6 = []string{
// localhost
"::1/128",
// ULA reserved
"fc00::/7",
// link local
"fe80::/10",
}
// Unroutable4 and Unroutable6 are well known unroutable address ranges
var Unroutable4, Unroutable6 []*net.IPNet
var unroutableCIDR4 = []string{
"0.0.0.0/8",
"192.0.0.0/26",
"192.0.2.0/24",
"192.88.99.0/24",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"224.0.0.0/4",
"240.0.0.0/4",
"255.255.255.255/32",
}
var unroutableCIDR6 = []string{
"ff00::/8",
}
// unResolvableDomains do not resolve to an IP address.
// Ref: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names
var unResolvableDomains = []string{
// Reverse DNS Lookup
".in-addr.arpa",
".ip6.arpa",
// RFC 6761: Users MAY assume that queries for "invalid" names will always return NXDOMAIN
// responses
".invalid",
}
// privateUseDomains are reserved for private use and have no central authority for consistent
// address resolution
// Ref: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names
var privateUseDomains = []string{
// RFC 8375: Reserved for home networks
".home.arpa",
// MDNS
".local",
// RFC 6761: No central authority for .test names
".test",
}
// RFC 6761: Users may assume that IPv4 and IPv6 address queries for localhost names will
// always resolve to the respective IP loopback address
const localHostDomain = ".localhost"
func init() {
Private4 = parseCIDR(privateCIDR4)
Private6 = parseCIDR(privateCIDR6)
Unroutable4 = parseCIDR(unroutableCIDR4)
Unroutable6 = parseCIDR(unroutableCIDR6)
}
func parseCIDR(cidrs []string) []*net.IPNet {
ipnets := make([]*net.IPNet, len(cidrs))
for i, cidr := range cidrs {
_, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
panic(err)
}
ipnets[i] = ipnet
}
return ipnets
}
// IsPublicAddr returns true if the IP part of the multiaddr is a publicly routable address
// or if it's a dns address without a special use domain e.g. .local.
func IsPublicAddr(a ma.Multiaddr) bool {
isPublic := false
ma.ForEach(a, func(c ma.Component) bool {
switch c.Protocol().Code {
case ma.P_IP6ZONE:
return true
case ma.P_IP4:
ip := net.IP(c.RawValue())
isPublic = !inAddrRange(ip, Private4) && !inAddrRange(ip, Unroutable4)
case ma.P_IP6:
ip := net.IP(c.RawValue())
isPublic = !inAddrRange(ip, Private6) && !inAddrRange(ip, Unroutable6)
case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR:
dnsAddr := c.Value()
isPublic = true
if isSubdomain(dnsAddr, localHostDomain) {
isPublic = false
return false
}
for _, ud := range unResolvableDomains {
if isSubdomain(dnsAddr, ud) {
isPublic = false
return false
}
}
for _, pd := range privateUseDomains {
if isSubdomain(dnsAddr, pd) {
isPublic = false
break
}
}
}
return false
})
return isPublic
}
// isSubdomain checks if child is sub domain of parent. It also returns true if child and parent are
// the same domain.
// Parent must have a "." prefix.
func isSubdomain(child, parent string) bool {
return strings.HasSuffix(child, parent) || child == parent[1:]
}
// IsPrivateAddr returns true if the IP part of the mutiaddr is in a private network
func IsPrivateAddr(a ma.Multiaddr) bool {
isPrivate := false
ma.ForEach(a, func(c ma.Component) bool {
switch c.Protocol().Code {
case ma.P_IP6ZONE:
return true
case ma.P_IP4:
isPrivate = inAddrRange(net.IP(c.RawValue()), Private4)
case ma.P_IP6:
isPrivate = inAddrRange(net.IP(c.RawValue()), Private6)
case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR:
dnsAddr := c.Value()
if isSubdomain(dnsAddr, localHostDomain) {
isPrivate = true
}
// We don't check for privateUseDomains because private use domains can
// resolve to public IP addresses
}
return false
})
return isPrivate
}
func inAddrRange(ip net.IP, ipnets []*net.IPNet) bool {
for _, ipnet := range ipnets {
if ipnet.Contains(ip) {
return true
}
}
return false
}

View File

@@ -0,0 +1,97 @@
package manet
import (
"fmt"
"net"
"sync"
ma "github.com/multiformats/go-multiaddr"
)
// FromNetAddrFunc is a generic function which converts a net.Addr to Multiaddress
type FromNetAddrFunc func(a net.Addr) (ma.Multiaddr, error)
// ToNetAddrFunc is a generic function which converts a Multiaddress to net.Addr
type ToNetAddrFunc func(ma ma.Multiaddr) (net.Addr, error)
var defaultCodecs = NewCodecMap()
func init() {
RegisterFromNetAddr(parseTCPNetAddr, "tcp", "tcp4", "tcp6")
RegisterFromNetAddr(parseUDPNetAddr, "udp", "udp4", "udp6")
RegisterFromNetAddr(parseIPNetAddr, "ip", "ip4", "ip6")
RegisterFromNetAddr(parseIPPlusNetAddr, "ip+net")
RegisterFromNetAddr(parseUnixNetAddr, "unix")
RegisterToNetAddr(parseBasicNetMaddr, "tcp", "udp", "ip6", "ip4", "unix")
}
// CodecMap holds a map of NetCodecs indexed by their Protocol ID
// along with parsers for the addresses they use.
// It is used to keep a list of supported network address codecs (protocols
// which addresses can be converted to and from multiaddresses).
type CodecMap struct {
addrParsers map[string]FromNetAddrFunc
maddrParsers map[string]ToNetAddrFunc
lk sync.Mutex
}
// NewCodecMap initializes and returns a CodecMap object.
func NewCodecMap() *CodecMap {
return &CodecMap{
addrParsers: make(map[string]FromNetAddrFunc),
maddrParsers: make(map[string]ToNetAddrFunc),
}
}
// RegisterFromNetAddr registers a conversion from net.Addr instances to multiaddrs.
func RegisterFromNetAddr(from FromNetAddrFunc, networks ...string) {
defaultCodecs.RegisterFromNetAddr(from, networks...)
}
// RegisterToNetAddr registers a conversion from multiaddrs to net.Addr instances.
func RegisterToNetAddr(to ToNetAddrFunc, protocols ...string) {
defaultCodecs.RegisterToNetAddr(to, protocols...)
}
// RegisterFromNetAddr registers a conversion from net.Addr instances to multiaddrs
func (cm *CodecMap) RegisterFromNetAddr(from FromNetAddrFunc, networks ...string) {
cm.lk.Lock()
defer cm.lk.Unlock()
for _, n := range networks {
cm.addrParsers[n] = from
}
}
// RegisterToNetAddr registers a conversion from multiaddrs to net.Addr instances
func (cm *CodecMap) RegisterToNetAddr(to ToNetAddrFunc, protocols ...string) {
cm.lk.Lock()
defer cm.lk.Unlock()
for _, p := range protocols {
cm.maddrParsers[p] = to
}
}
func (cm *CodecMap) getAddrParser(net string) (FromNetAddrFunc, error) {
cm.lk.Lock()
defer cm.lk.Unlock()
parser, ok := cm.addrParsers[net]
if !ok {
return nil, fmt.Errorf("unknown network %v", net)
}
return parser, nil
}
func (cm *CodecMap) getMaddrParser(name string) (ToNetAddrFunc, error) {
cm.lk.Lock()
defer cm.lk.Unlock()
p, ok := cm.maddrParsers[name]
if !ok {
return nil, fmt.Errorf("network not supported: %s", name)
}
return p, nil
}

View File

@@ -0,0 +1,83 @@
package manet
import (
"fmt"
ma "github.com/multiformats/go-multiaddr"
)
// ResolveUnspecifiedAddress expands an unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to
// use the known local interfaces. If ifaceAddr is nil, we request interface addresses
// from the network stack. (this is so you can provide a cached value if resolving many addrs)
func ResolveUnspecifiedAddress(resolve ma.Multiaddr, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
// split address into its components
split := ma.Split(resolve)
// if first component (ip) is not unspecified, use it as is.
if !IsIPUnspecified(split[0]) {
return []ma.Multiaddr{resolve}, nil
}
out := make([]ma.Multiaddr, 0, len(ifaceAddrs))
for _, ia := range ifaceAddrs {
// must match the first protocol to be resolve.
if ia.Protocols()[0].Code != resolve.Protocols()[0].Code {
continue
}
split[0] = ia
joined := ma.Join(split...)
out = append(out, joined)
}
if len(out) < 1 {
return nil, fmt.Errorf("failed to resolve: %s", resolve)
}
return out, nil
}
// ResolveUnspecifiedAddresses expands unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to
// use the known local interfaces.
func ResolveUnspecifiedAddresses(unspecAddrs, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
// todo optimize: only fetch these if we have a "any" addr.
if len(ifaceAddrs) < 1 {
var err error
ifaceAddrs, err = interfaceAddresses()
if err != nil {
return nil, err
}
}
var outputAddrs []ma.Multiaddr
for _, a := range unspecAddrs {
// unspecified?
resolved, err := ResolveUnspecifiedAddress(a, ifaceAddrs)
if err != nil {
continue // optimistic. if we can't resolve anything, we'll know at the bottom.
}
outputAddrs = append(outputAddrs, resolved...)
}
if len(outputAddrs) < 1 {
return nil, fmt.Errorf("failed to specify addrs: %s", unspecAddrs)
}
return outputAddrs, nil
}
// interfaceAddresses returns a list of addresses associated with local machine
// Note: we do not return link local addresses. IP loopback is ok, because we
// may be connecting to other nodes in the same machine.
func interfaceAddresses() ([]ma.Multiaddr, error) {
maddrs, err := InterfaceMultiaddrs()
if err != nil {
return nil, err
}
var out []ma.Multiaddr
for _, a := range maddrs {
if IsIP6LinkLocal(a) {
continue
}
out = append(out, a)
}
return out, nil
}

View File

@@ -0,0 +1,23 @@
{
"author": "multiformats",
"bugs": {
"url": "https://github.com/multiformats/go-multiaddr/issues"
},
"gx": {
"dvcsimport": "github.com/multiformats/go-multiaddr"
},
"gxDependencies": [
{
"hash": "QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW",
"name": "go-multihash",
"version": "1.0.9"
}
],
"gxVersion": "0.9.0",
"language": "go",
"license": "MIT",
"name": "go-multiaddr",
"releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
"version": "1.4.1"
}

102
vendor/github.com/multiformats/go-multiaddr/protocol.go generated vendored Normal file
View File

@@ -0,0 +1,102 @@
package multiaddr
import (
"fmt"
"strings"
)
// These are special sizes
const (
LengthPrefixedVarSize = -1
)
// Protocol is a Multiaddr protocol description structure.
type Protocol struct {
// Name is the string representation of the protocol code. E.g., ip4,
// ip6, tcp, udp, etc.
Name string
// Code is the protocol's multicodec (a normal, non-varint number).
Code int
// VCode is a precomputed varint encoded version of Code.
VCode []byte
// Size is the size of the argument to this protocol.
//
// * Size == 0 means this protocol takes no argument.
// * Size > 0 means this protocol takes a constant sized argument.
// * Size < 0 means this protocol takes a variable length, varint
// prefixed argument.
Size int // a size of -1 indicates a length-prefixed variable size
// Path indicates a path protocol (e.g., unix). When parsing multiaddr
// strings, path protocols consume the remainder of the address instead
// of stopping at the next forward slash.
//
// Size must be LengthPrefixedVarSize.
Path bool
// Transcoder converts between the byte representation and the string
// representation of this protocol's argument (if any).
//
// This should only be non-nil if Size != 0
Transcoder Transcoder
}
var protocolsByName = map[string]Protocol{}
var protocolsByCode = map[int]Protocol{}
// Protocols is the list of multiaddr protocols supported by this module.
var Protocols = []Protocol{}
func AddProtocol(p Protocol) error {
if _, ok := protocolsByName[p.Name]; ok {
return fmt.Errorf("protocol by the name %q already exists", p.Name)
}
if _, ok := protocolsByCode[p.Code]; ok {
return fmt.Errorf("protocol code %d already taken by %q", p.Code, p.Code)
}
if p.Size != 0 && p.Transcoder == nil {
return fmt.Errorf("protocols with arguments must define transcoders")
}
if p.Path && p.Size >= 0 {
return fmt.Errorf("path protocols must have variable-length sizes")
}
Protocols = append(Protocols, p)
protocolsByName[p.Name] = p
protocolsByCode[p.Code] = p
return nil
}
// ProtocolWithName returns the Protocol description with given string name.
func ProtocolWithName(s string) Protocol {
return protocolsByName[s]
}
// ProtocolWithCode returns the Protocol description with given protocol code.
func ProtocolWithCode(c int) Protocol {
return protocolsByCode[c]
}
// ProtocolsWithString returns a slice of protocols matching given string.
func ProtocolsWithString(s string) ([]Protocol, error) {
s = strings.Trim(s, "/")
sp := strings.Split(s, "/")
if len(sp) == 0 {
return nil, nil
}
t := make([]Protocol, len(sp))
for i, name := range sp {
p := ProtocolWithName(name)
if p.Code == 0 {
return nil, fmt.Errorf("no protocol with name: %s", name)
}
t[i] = p
}
return t, nil
}

View File

@@ -0,0 +1,325 @@
package multiaddr
// You **MUST** register your multicodecs with
// https://github.com/multiformats/multicodec before adding them here.
const (
P_IP4 = 4
P_TCP = 6
P_DNS = 53 // 4 or 6
P_DNS4 = 54
P_DNS6 = 55
P_DNSADDR = 56
P_UDP = 273
P_DCCP = 33
P_IP6 = 41
P_IP6ZONE = 42
P_IPCIDR = 43
P_QUIC = 460
P_QUIC_V1 = 461
P_WEBTRANSPORT = 465
P_CERTHASH = 466
P_SCTP = 132
P_CIRCUIT = 290
P_UDT = 301
P_UTP = 302
P_UNIX = 400
P_P2P = 421
P_IPFS = P_P2P // alias for backwards compatibility
P_HTTP = 480
P_HTTPS = 443 // deprecated alias for /tls/http
P_ONION = 444 // also for backwards compatibility
P_ONION3 = 445
P_GARLIC64 = 446
P_GARLIC32 = 447
P_P2P_WEBRTC_DIRECT = 276 // Deprecated. use webrtc-direct instead
P_TLS = 448
P_SNI = 449
P_NOISE = 454
P_WS = 477
P_WSS = 478 // deprecated alias for /tls/ws
P_PLAINTEXTV2 = 7367777
P_WEBRTC_DIRECT = 280
P_WEBRTC = 281
)
var (
protoIP4 = Protocol{
Name: "ip4",
Code: P_IP4,
VCode: CodeToVarint(P_IP4),
Size: 32,
Path: false,
Transcoder: TranscoderIP4,
}
protoTCP = Protocol{
Name: "tcp",
Code: P_TCP,
VCode: CodeToVarint(P_TCP),
Size: 16,
Path: false,
Transcoder: TranscoderPort,
}
protoDNS = Protocol{
Code: P_DNS,
Size: LengthPrefixedVarSize,
Name: "dns",
VCode: CodeToVarint(P_DNS),
Transcoder: TranscoderDns,
}
protoDNS4 = Protocol{
Code: P_DNS4,
Size: LengthPrefixedVarSize,
Name: "dns4",
VCode: CodeToVarint(P_DNS4),
Transcoder: TranscoderDns,
}
protoDNS6 = Protocol{
Code: P_DNS6,
Size: LengthPrefixedVarSize,
Name: "dns6",
VCode: CodeToVarint(P_DNS6),
Transcoder: TranscoderDns,
}
protoDNSADDR = Protocol{
Code: P_DNSADDR,
Size: LengthPrefixedVarSize,
Name: "dnsaddr",
VCode: CodeToVarint(P_DNSADDR),
Transcoder: TranscoderDns,
}
protoUDP = Protocol{
Name: "udp",
Code: P_UDP,
VCode: CodeToVarint(P_UDP),
Size: 16,
Path: false,
Transcoder: TranscoderPort,
}
protoDCCP = Protocol{
Name: "dccp",
Code: P_DCCP,
VCode: CodeToVarint(P_DCCP),
Size: 16,
Path: false,
Transcoder: TranscoderPort,
}
protoIP6 = Protocol{
Name: "ip6",
Code: P_IP6,
VCode: CodeToVarint(P_IP6),
Size: 128,
Transcoder: TranscoderIP6,
}
protoIPCIDR = Protocol{
Name: "ipcidr",
Code: P_IPCIDR,
VCode: CodeToVarint(P_IPCIDR),
Size: 8,
Transcoder: TranscoderIPCIDR,
}
// these require varint
protoIP6ZONE = Protocol{
Name: "ip6zone",
Code: P_IP6ZONE,
VCode: CodeToVarint(P_IP6ZONE),
Size: LengthPrefixedVarSize,
Path: false,
Transcoder: TranscoderIP6Zone,
}
protoSCTP = Protocol{
Name: "sctp",
Code: P_SCTP,
VCode: CodeToVarint(P_SCTP),
Size: 16,
Transcoder: TranscoderPort,
}
protoCIRCUIT = Protocol{
Code: P_CIRCUIT,
Size: 0,
Name: "p2p-circuit",
VCode: CodeToVarint(P_CIRCUIT),
}
protoONION2 = Protocol{
Name: "onion",
Code: P_ONION,
VCode: CodeToVarint(P_ONION),
Size: 96,
Transcoder: TranscoderOnion,
}
protoONION3 = Protocol{
Name: "onion3",
Code: P_ONION3,
VCode: CodeToVarint(P_ONION3),
Size: 296,
Transcoder: TranscoderOnion3,
}
protoGARLIC64 = Protocol{
Name: "garlic64",
Code: P_GARLIC64,
VCode: CodeToVarint(P_GARLIC64),
Size: LengthPrefixedVarSize,
Transcoder: TranscoderGarlic64,
}
protoGARLIC32 = Protocol{
Name: "garlic32",
Code: P_GARLIC32,
VCode: CodeToVarint(P_GARLIC32),
Size: LengthPrefixedVarSize,
Transcoder: TranscoderGarlic32,
}
protoUTP = Protocol{
Name: "utp",
Code: P_UTP,
VCode: CodeToVarint(P_UTP),
}
protoUDT = Protocol{
Name: "udt",
Code: P_UDT,
VCode: CodeToVarint(P_UDT),
}
protoQUIC = Protocol{
Name: "quic",
Code: P_QUIC,
VCode: CodeToVarint(P_QUIC),
}
protoQUICV1 = Protocol{
Name: "quic-v1",
Code: P_QUIC_V1,
VCode: CodeToVarint(P_QUIC_V1),
}
protoWEBTRANSPORT = Protocol{
Name: "webtransport",
Code: P_WEBTRANSPORT,
VCode: CodeToVarint(P_WEBTRANSPORT),
}
protoCERTHASH = Protocol{
Name: "certhash",
Code: P_CERTHASH,
VCode: CodeToVarint(P_CERTHASH),
Size: LengthPrefixedVarSize,
Transcoder: TranscoderCertHash,
}
protoHTTP = Protocol{
Name: "http",
Code: P_HTTP,
VCode: CodeToVarint(P_HTTP),
}
protoHTTPS = Protocol{
Name: "https",
Code: P_HTTPS,
VCode: CodeToVarint(P_HTTPS),
}
protoP2P = Protocol{
Name: "p2p",
Code: P_P2P,
VCode: CodeToVarint(P_P2P),
Size: LengthPrefixedVarSize,
Transcoder: TranscoderP2P,
}
protoUNIX = Protocol{
Name: "unix",
Code: P_UNIX,
VCode: CodeToVarint(P_UNIX),
Size: LengthPrefixedVarSize,
Path: true,
Transcoder: TranscoderUnix,
}
protoP2P_WEBRTC_DIRECT = Protocol{
Name: "p2p-webrtc-direct",
Code: P_P2P_WEBRTC_DIRECT,
VCode: CodeToVarint(P_P2P_WEBRTC_DIRECT),
}
protoTLS = Protocol{
Name: "tls",
Code: P_TLS,
VCode: CodeToVarint(P_TLS),
}
protoSNI = Protocol{
Name: "sni",
Size: LengthPrefixedVarSize,
Code: P_SNI,
VCode: CodeToVarint(P_SNI),
Transcoder: TranscoderDns,
}
protoNOISE = Protocol{
Name: "noise",
Code: P_NOISE,
VCode: CodeToVarint(P_NOISE),
}
protoPlaintextV2 = Protocol{
Name: "plaintextv2",
Code: P_PLAINTEXTV2,
VCode: CodeToVarint(P_PLAINTEXTV2),
}
protoWS = Protocol{
Name: "ws",
Code: P_WS,
VCode: CodeToVarint(P_WS),
}
protoWSS = Protocol{
Name: "wss",
Code: P_WSS,
VCode: CodeToVarint(P_WSS),
}
protoWebRTCDirect = Protocol{
Name: "webrtc-direct",
Code: P_WEBRTC_DIRECT,
VCode: CodeToVarint(P_WEBRTC_DIRECT),
}
protoWebRTC = Protocol{
Name: "webrtc",
Code: P_WEBRTC,
VCode: CodeToVarint(P_WEBRTC),
}
)
func init() {
for _, p := range []Protocol{
protoIP4,
protoTCP,
protoDNS,
protoDNS4,
protoDNS6,
protoDNSADDR,
protoUDP,
protoDCCP,
protoIP6,
protoIP6ZONE,
protoIPCIDR,
protoSCTP,
protoCIRCUIT,
protoONION2,
protoONION3,
protoGARLIC64,
protoGARLIC32,
protoUTP,
protoUDT,
protoQUIC,
protoQUICV1,
protoWEBTRANSPORT,
protoCERTHASH,
protoHTTP,
protoHTTPS,
protoP2P,
protoUNIX,
protoP2P_WEBRTC_DIRECT,
protoTLS,
protoSNI,
protoNOISE,
protoWS,
protoWSS,
protoPlaintextV2,
protoWebRTCDirect,
protoWebRTC,
} {
if err := AddProtocol(p); err != nil {
panic(err)
}
}
// explicitly set both of these
protocolsByName["p2p"] = protoP2P
protocolsByName["ipfs"] = protoP2P
}

View File

@@ -0,0 +1,393 @@
package multiaddr
import (
"bytes"
"encoding/base32"
"encoding/base64"
"encoding/binary"
"fmt"
"net"
"strconv"
"strings"
"github.com/ipfs/go-cid"
"github.com/multiformats/go-multibase"
mh "github.com/multiformats/go-multihash"
)
type Transcoder interface {
// Validates and encodes to bytes a multiaddr that's in the string representation.
StringToBytes(string) ([]byte, error)
// Validates and decodes to a string a multiaddr that's in the bytes representation.
BytesToString([]byte) (string, error)
// Validates bytes when parsing a multiaddr that's already in the bytes representation.
ValidateBytes([]byte) error
}
func NewTranscoderFromFunctions(
s2b func(string) ([]byte, error),
b2s func([]byte) (string, error),
val func([]byte) error,
) Transcoder {
return twrp{s2b, b2s, val}
}
type twrp struct {
strtobyte func(string) ([]byte, error)
bytetostr func([]byte) (string, error)
validbyte func([]byte) error
}
func (t twrp) StringToBytes(s string) ([]byte, error) {
return t.strtobyte(s)
}
func (t twrp) BytesToString(b []byte) (string, error) {
return t.bytetostr(b)
}
func (t twrp) ValidateBytes(b []byte) error {
if t.validbyte == nil {
return nil
}
return t.validbyte(b)
}
var TranscoderIP4 = NewTranscoderFromFunctions(ip4StB, ip4BtS, nil)
var TranscoderIP6 = NewTranscoderFromFunctions(ip6StB, ip6BtS, nil)
var TranscoderIP6Zone = NewTranscoderFromFunctions(ip6zoneStB, ip6zoneBtS, ip6zoneVal)
var TranscoderIPCIDR = NewTranscoderFromFunctions(ipcidrStB, ipcidrBtS, nil)
func ipcidrBtS(b []byte) (string, error) {
if len(b) != 1 {
return "", fmt.Errorf("invalid length (should be == 1)")
}
return strconv.Itoa(int(b[0])), nil
}
func ipcidrStB(s string) ([]byte, error) {
ipMask, err := strconv.ParseUint(s, 10, 8)
if err != nil {
return nil, err
}
return []byte{byte(uint8(ipMask))}, nil
}
func ip4StB(s string) ([]byte, error) {
i := net.ParseIP(s).To4()
if i == nil {
return nil, fmt.Errorf("failed to parse ip4 addr: %s", s)
}
return i, nil
}
func ip6zoneStB(s string) ([]byte, error) {
if len(s) == 0 {
return nil, fmt.Errorf("empty ip6zone")
}
if strings.Contains(s, "/") {
return nil, fmt.Errorf("IPv6 zone ID contains '/': %s", s)
}
return []byte(s), nil
}
func ip6zoneBtS(b []byte) (string, error) {
if len(b) == 0 {
return "", fmt.Errorf("invalid length (should be > 0)")
}
return string(b), nil
}
func ip6zoneVal(b []byte) error {
if len(b) == 0 {
return fmt.Errorf("invalid length (should be > 0)")
}
// Not supported as this would break multiaddrs.
if bytes.IndexByte(b, '/') >= 0 {
return fmt.Errorf("IPv6 zone ID contains '/': %s", string(b))
}
return nil
}
func ip6StB(s string) ([]byte, error) {
i := net.ParseIP(s).To16()
if i == nil {
return nil, fmt.Errorf("failed to parse ip6 addr: %s", s)
}
return i, nil
}
func ip6BtS(b []byte) (string, error) {
ip := net.IP(b)
if ip4 := ip.To4(); ip4 != nil {
// Go fails to prepend the `::ffff:` part.
return "::ffff:" + ip4.String(), nil
}
return ip.String(), nil
}
func ip4BtS(b []byte) (string, error) {
return net.IP(b).String(), nil
}
var TranscoderPort = NewTranscoderFromFunctions(portStB, portBtS, nil)
func portStB(s string) ([]byte, error) {
i, err := strconv.Atoi(s)
if err != nil {
return nil, fmt.Errorf("failed to parse port addr: %s", err)
}
if i >= 65536 {
return nil, fmt.Errorf("failed to parse port addr: %s", "greater than 65536")
}
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, uint16(i))
return b, nil
}
func portBtS(b []byte) (string, error) {
i := binary.BigEndian.Uint16(b)
return strconv.Itoa(int(i)), nil
}
var TranscoderOnion = NewTranscoderFromFunctions(onionStB, onionBtS, nil)
func onionStB(s string) ([]byte, error) {
addr := strings.Split(s, ":")
if len(addr) != 2 {
return nil, fmt.Errorf("failed to parse onion addr: %s does not contain a port number", s)
}
// onion address without the ".onion" substring
if len(addr[0]) != 16 {
return nil, fmt.Errorf("failed to parse onion addr: %s not a Tor onion address", s)
}
onionHostBytes, err := base32.StdEncoding.DecodeString(strings.ToUpper(addr[0]))
if err != nil {
return nil, fmt.Errorf("failed to decode base32 onion addr: %s %s", s, err)
}
// onion port number
i, err := strconv.Atoi(addr[1])
if err != nil {
return nil, fmt.Errorf("failed to parse onion addr: %s", err)
}
if i >= 65536 {
return nil, fmt.Errorf("failed to parse onion addr: %s", "port greater than 65536")
}
if i < 1 {
return nil, fmt.Errorf("failed to parse onion addr: %s", "port less than 1")
}
onionPortBytes := make([]byte, 2)
binary.BigEndian.PutUint16(onionPortBytes, uint16(i))
bytes := []byte{}
bytes = append(bytes, onionHostBytes...)
bytes = append(bytes, onionPortBytes...)
return bytes, nil
}
func onionBtS(b []byte) (string, error) {
addr := strings.ToLower(base32.StdEncoding.EncodeToString(b[0:10]))
port := binary.BigEndian.Uint16(b[10:12])
return addr + ":" + strconv.Itoa(int(port)), nil
}
var TranscoderOnion3 = NewTranscoderFromFunctions(onion3StB, onion3BtS, nil)
func onion3StB(s string) ([]byte, error) {
addr := strings.Split(s, ":")
if len(addr) != 2 {
return nil, fmt.Errorf("failed to parse onion addr: %s does not contain a port number", s)
}
// onion address without the ".onion" substring
if len(addr[0]) != 56 {
return nil, fmt.Errorf("failed to parse onion addr: %s not a Tor onionv3 address. len == %d", s, len(addr[0]))
}
onionHostBytes, err := base32.StdEncoding.DecodeString(strings.ToUpper(addr[0]))
if err != nil {
return nil, fmt.Errorf("failed to decode base32 onion addr: %s %s", s, err)
}
// onion port number
i, err := strconv.Atoi(addr[1])
if err != nil {
return nil, fmt.Errorf("failed to parse onion addr: %s", err)
}
if i >= 65536 {
return nil, fmt.Errorf("failed to parse onion addr: %s", "port greater than 65536")
}
if i < 1 {
return nil, fmt.Errorf("failed to parse onion addr: %s", "port less than 1")
}
onionPortBytes := make([]byte, 2)
binary.BigEndian.PutUint16(onionPortBytes, uint16(i))
bytes := []byte{}
bytes = append(bytes, onionHostBytes[0:35]...)
bytes = append(bytes, onionPortBytes...)
return bytes, nil
}
func onion3BtS(b []byte) (string, error) {
addr := strings.ToLower(base32.StdEncoding.EncodeToString(b[0:35]))
port := binary.BigEndian.Uint16(b[35:37])
str := addr + ":" + strconv.Itoa(int(port))
return str, nil
}
var TranscoderGarlic64 = NewTranscoderFromFunctions(garlic64StB, garlic64BtS, garlic64Validate)
// i2p uses an alternate character set for base64 addresses. This returns an appropriate encoder.
var garlicBase64Encoding = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~")
func garlic64StB(s string) ([]byte, error) {
// i2p base64 address will be between 516 and 616 characters long, depending on
// certificate type
if len(s) < 516 || len(s) > 616 {
return nil, fmt.Errorf("failed to parse garlic addr: %s not an i2p base64 address. len: %d", s, len(s))
}
garlicHostBytes, err := garlicBase64Encoding.DecodeString(s)
if err != nil {
return nil, fmt.Errorf("failed to decode base64 i2p addr: %s %s", s, err)
}
return garlicHostBytes, nil
}
func garlic64BtS(b []byte) (string, error) {
if err := garlic64Validate(b); err != nil {
return "", err
}
addr := garlicBase64Encoding.EncodeToString(b)
return addr, nil
}
func garlic64Validate(b []byte) error {
// A garlic64 address will always be greater than 386 bytes long when encoded.
if len(b) < 386 {
return fmt.Errorf("failed to validate garlic addr: %s not an i2p base64 address. len: %d", b, len(b))
}
return nil
}
var TranscoderGarlic32 = NewTranscoderFromFunctions(garlic32StB, garlic32BtS, garlic32Validate)
var garlicBase32Encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567")
func garlic32StB(s string) ([]byte, error) {
// an i2p base32 address with a length of greater than 55 characters is
// using an Encrypted Leaseset v2. all other base32 addresses will always be
// exactly 52 characters
if len(s) < 55 && len(s) != 52 {
return nil, fmt.Errorf("failed to parse garlic addr: %s not a i2p base32 address. len: %d", s, len(s))
}
for len(s)%8 != 0 {
s += "="
}
garlicHostBytes, err := garlicBase32Encoding.DecodeString(s)
if err != nil {
return nil, fmt.Errorf("failed to decode base32 garlic addr: %s, err: %v len: %v", s, err, len(s))
}
return garlicHostBytes, nil
}
func garlic32BtS(b []byte) (string, error) {
if err := garlic32Validate(b); err != nil {
return "", err
}
return strings.TrimRight(garlicBase32Encoding.EncodeToString(b), "="), nil
}
func garlic32Validate(b []byte) error {
// an i2p base64 for an Encrypted Leaseset v2 will be at least 35 bytes
// long other than that, they will be exactly 32 bytes
if len(b) < 35 && len(b) != 32 {
return fmt.Errorf("failed to validate garlic addr: %s not an i2p base32 address. len: %d", b, len(b))
}
return nil
}
var TranscoderP2P = NewTranscoderFromFunctions(p2pStB, p2pBtS, p2pVal)
// The encoded peer ID can either be a CID of a key or a raw multihash (identity
// or sha256-256).
func p2pStB(s string) ([]byte, error) {
// check if the address is a base58 encoded sha256 or identity multihash
if strings.HasPrefix(s, "Qm") || strings.HasPrefix(s, "1") {
m, err := mh.FromB58String(s)
if err != nil {
return nil, fmt.Errorf("failed to parse p2p addr: %s %s", s, err)
}
return m, nil
}
// check if the address is a CID
c, err := cid.Decode(s)
if err != nil {
return nil, fmt.Errorf("failed to parse p2p addr: %s %s", s, err)
}
if ty := c.Type(); ty == cid.Libp2pKey {
return c.Hash(), nil
} else {
return nil, fmt.Errorf("failed to parse p2p addr: %s has the invalid codec %d", s, ty)
}
}
func p2pVal(b []byte) error {
_, err := mh.Cast(b)
return err
}
func p2pBtS(b []byte) (string, error) {
m, err := mh.Cast(b)
if err != nil {
return "", err
}
return m.B58String(), nil
}
var TranscoderUnix = NewTranscoderFromFunctions(unixStB, unixBtS, nil)
func unixStB(s string) ([]byte, error) {
return []byte(s), nil
}
func unixBtS(b []byte) (string, error) {
return string(b), nil
}
var TranscoderDns = NewTranscoderFromFunctions(dnsStB, dnsBtS, dnsVal)
func dnsVal(b []byte) error {
if bytes.IndexByte(b, '/') >= 0 {
return fmt.Errorf("domain name %q contains a slash", string(b))
}
return nil
}
func dnsStB(s string) ([]byte, error) {
return []byte(s), nil
}
func dnsBtS(b []byte) (string, error) {
return string(b), nil
}
var TranscoderCertHash = NewTranscoderFromFunctions(certHashStB, certHashBtS, nil)
func certHashStB(s string) ([]byte, error) {
_, data, err := multibase.Decode(s)
if err != nil {
return nil, err
}
if _, err := mh.Decode(data); err != nil {
return nil, err
}
return data, nil
}
func certHashBtS(b []byte) (string, error) {
return multibase.Encode(multibase.Base64url, b)
}

180
vendor/github.com/multiformats/go-multiaddr/util.go generated vendored Normal file
View File

@@ -0,0 +1,180 @@
package multiaddr
import "fmt"
// Split returns the sub-address portions of a multiaddr.
func Split(m Multiaddr) []Multiaddr {
if _, ok := m.(*Component); ok {
return []Multiaddr{m}
}
var addrs []Multiaddr
ForEach(m, func(c Component) bool {
addrs = append(addrs, &c)
return true
})
return addrs
}
// Join returns a combination of addresses.
func Join(ms ...Multiaddr) Multiaddr {
switch len(ms) {
case 0:
// empty multiaddr, unfortunately, we have callers that rely on
// this contract.
return &multiaddr{}
case 1:
return ms[0]
}
length := 0
bs := make([][]byte, len(ms))
for i, m := range ms {
bs[i] = m.Bytes()
length += len(bs[i])
}
bidx := 0
b := make([]byte, length)
for _, mb := range bs {
bidx += copy(b[bidx:], mb)
}
return &multiaddr{bytes: b}
}
// Cast re-casts a byte slice as a multiaddr. will panic if it fails to parse.
func Cast(b []byte) Multiaddr {
m, err := NewMultiaddrBytes(b)
if err != nil {
panic(fmt.Errorf("multiaddr failed to parse: %s", err))
}
return m
}
// StringCast like Cast, but parses a string. Will also panic if it fails to parse.
func StringCast(s string) Multiaddr {
m, err := NewMultiaddr(s)
if err != nil {
panic(fmt.Errorf("multiaddr failed to parse: %s", err))
}
return m
}
// SplitFirst returns the first component and the rest of the multiaddr.
func SplitFirst(m Multiaddr) (*Component, Multiaddr) {
// Shortcut if we already have a component
if c, ok := m.(*Component); ok {
return c, nil
}
b := m.Bytes()
if len(b) == 0 {
return nil, nil
}
n, c, err := readComponent(b)
if err != nil {
panic(err)
}
if len(b) == n {
return &c, nil
}
return &c, &multiaddr{b[n:]}
}
// SplitLast returns the rest of the multiaddr and the last component.
func SplitLast(m Multiaddr) (Multiaddr, *Component) {
// Shortcut if we already have a component
if c, ok := m.(*Component); ok {
return nil, c
}
b := m.Bytes()
if len(b) == 0 {
return nil, nil
}
var (
c Component
err error
offset int
)
for {
var n int
n, c, err = readComponent(b[offset:])
if err != nil {
panic(err)
}
if len(b) == n+offset {
// Reached end
if offset == 0 {
// Only one component
return nil, &c
}
return &multiaddr{b[:offset]}, &c
}
offset += n
}
}
// SplitFunc splits the multiaddr when the callback first returns true. The
// component on which the callback first returns will be included in the
// *second* multiaddr.
func SplitFunc(m Multiaddr, cb func(Component) bool) (Multiaddr, Multiaddr) {
// Shortcut if we already have a component
if c, ok := m.(*Component); ok {
if cb(*c) {
return nil, m
}
return m, nil
}
b := m.Bytes()
if len(b) == 0 {
return nil, nil
}
var (
c Component
err error
offset int
)
for offset < len(b) {
var n int
n, c, err = readComponent(b[offset:])
if err != nil {
panic(err)
}
if cb(c) {
break
}
offset += n
}
switch offset {
case 0:
return nil, m
case len(b):
return m, nil
default:
return &multiaddr{b[:offset]}, &multiaddr{b[offset:]}
}
}
// ForEach walks over the multiaddr, component by component.
//
// This function iterates over components *by value* to avoid allocating.
func ForEach(m Multiaddr, cb func(c Component) bool) {
// Shortcut if we already have a component
if c, ok := m.(*Component); ok {
cb(*c)
return
}
b := m.Bytes()
for len(b) > 0 {
n, c, err := readComponent(b)
if err != nil {
panic(err)
}
if !cb(c) {
return
}
b = b[n:]
}
}

27
vendor/github.com/multiformats/go-multiaddr/varint.go generated vendored Normal file
View File

@@ -0,0 +1,27 @@
package multiaddr
import (
"math"
"github.com/multiformats/go-varint"
)
// CodeToVarint converts an integer to a varint-encoded []byte
func CodeToVarint(num int) []byte {
if num < 0 || num > math.MaxInt32 {
panic("invalid code")
}
return varint.ToUvarint(uint64(num))
}
func ReadVarintCode(b []byte) (int, int, error) {
code, n, err := varint.FromUvarint(b)
if err != nil {
return 0, 0, err
}
if code > math.MaxInt32 {
// we only allow 32bit codes.
return 0, 0, varint.ErrOverflow
}
return int(code), n, err
}

View File

@@ -0,0 +1,3 @@
{
"version": "v0.12.0"
}

View File

@@ -0,0 +1 @@
comment: off

View File

@@ -0,0 +1,3 @@
*.swp
multibase-conv/multibase-conv

View File

@@ -0,0 +1,3 @@
[submodule "spec"]
path = spec
url = https://github.com/multiformats/multibase.git

21
vendor/github.com/multiformats/go-multibase/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Protocol Labs Inc.
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.

7
vendor/github.com/multiformats/go-multibase/Makefile generated vendored Normal file
View File

@@ -0,0 +1,7 @@
test: deps
go test -count=1 -race -v ./...
export IPFS_API ?= v04x.ipfs.io
deps:
go get -t ./...

31
vendor/github.com/multiformats/go-multibase/README.md generated vendored Normal file
View File

@@ -0,0 +1,31 @@
# go-multibase
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs)
[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
[![Travis CI](https://img.shields.io/travis/multiformats/go-multibase.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-multibase)
[![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-multibase.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-multibase?branch=master)
> Implementation of [multibase](https://github.com/multiformats/multibase) -self identifying base encodings- in Go.
## Install
`go-multibase` is a standard Go module which can be installed with:
```sh
go get github.com/multiformats/go-multibase
```
## Contribute
Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multibase/issues).
Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
## License
[MIT](LICENSE) © 2016 Protocol Labs Inc.

21
vendor/github.com/multiformats/go-multibase/base16.go generated vendored Normal file
View File

@@ -0,0 +1,21 @@
package multibase
func hexEncodeToStringUpper(src []byte) string {
dst := make([]byte, len(src)*2)
hexEncodeUpper(dst, src)
return string(dst)
}
var hexTableUppers = [16]byte{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F',
}
func hexEncodeUpper(dst, src []byte) int {
for i, v := range src {
dst[i*2] = hexTableUppers[v>>4]
dst[i*2+1] = hexTableUppers[v&0x0f]
}
return len(src) * 2
}

52
vendor/github.com/multiformats/go-multibase/base2.go generated vendored Normal file
View File

@@ -0,0 +1,52 @@
package multibase
import (
"fmt"
"strconv"
"strings"
)
// binaryEncodeToString takes an array of bytes and returns
// multibase binary representation
func binaryEncodeToString(src []byte) string {
dst := make([]byte, len(src)*8)
encodeBinary(dst, src)
return string(dst)
}
// encodeBinary takes the src and dst bytes and converts each
// byte to their binary rep using power reduction method
func encodeBinary(dst []byte, src []byte) {
for i, b := range src {
for j := 0; j < 8; j++ {
if b&(1<<uint(7-j)) == 0 {
dst[i*8+j] = '0'
} else {
dst[i*8+j] = '1'
}
}
}
}
// decodeBinaryString takes multibase binary representation
// and returns a byte array
func decodeBinaryString(s string) ([]byte, error) {
if len(s)&7 != 0 {
// prepend the padding
s = strings.Repeat("0", 8-len(s)&7) + s
}
data := make([]byte, len(s)>>3)
for i, dstIndex := 0, 0; i < len(s); i = i + 8 {
value, err := strconv.ParseInt(s[i:i+8], 2, 0)
if err != nil {
return nil, fmt.Errorf("error while conversion: %s", err)
}
data[dstIndex] = byte(value)
dstIndex++
}
return data, nil
}

View File

@@ -0,0 +1,95 @@
package multibase
import (
"strconv"
"strings"
"unicode/utf8"
)
var base256emojiTable = [256]rune{
// Curated list, this is just a list of things that *somwhat* are related to our comunity
'🚀', '🪐', '☄', '🛰', '🌌', // Space
'🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘', // Moon
'🌍', '🌏', '🌎', // Our Home, for now (earth)
'🐉', // Dragon!!!
'☀', // Our Garden, for now (sol)
'💻', '🖥', '💾', '💿', // Computer
// The rest is completed from https://home.unicode.org/emoji/emoji-frequency/ at the time of creation (december 2021) (the data is from 2019), most used first until we reach 256.
// We exclude modifier based emojies (such as flags) as they are bigger than one single codepoint.
// Some other emojies were removed adhoc for various reasons.
'😂', '❤', '😍', '🤣', '😊', '🙏', '💕', '😭', '😘', '👍',
'😅', '👏', '😁', '🔥', '🥰', '💔', '💖', '💙', '😢', '🤔',
'😆', '🙄', '💪', '😉', '☺', '👌', '🤗', '💜', '😔', '😎',
'😇', '🌹', '🤦', '🎉', '💞', '✌', '✨', '🤷', '😱', '😌',
'🌸', '🙌', '😋', '💗', '💚', '😏', '💛', '🙂', '💓', '🤩',
'😄', '😀', '🖤', '😃', '💯', '🙈', '👇', '🎶', '😒', '🤭',
'❣', '😜', '💋', '👀', '😪', '😑', '💥', '🙋', '😞', '😩',
'😡', '🤪', '👊', '🥳', '😥', '🤤', '👉', '💃', '😳', '✋',
'😚', '😝', '😴', '🌟', '😬', '🙃', '🍀', '🌷', '😻', '😓',
'⭐', '✅', '🥺', '🌈', '😈', '🤘', '💦', '✔', '😣', '🏃',
'💐', '☹', '🎊', '💘', '😠', '☝', '😕', '🌺', '🎂', '🌻',
'😐', '🖕', '💝', '🙊', '😹', '🗣', '💫', '💀', '👑', '🎵',
'🤞', '😛', '🔴', '😤', '🌼', '😫', '⚽', '🤙', '☕', '🏆',
'🤫', '👈', '😮', '🙆', '🍻', '🍃', '🐶', '💁', '😲', '🌿',
'🧡', '🎁', '⚡', '🌞', '🎈', '❌', '✊', '👋', '😰', '🤨',
'😶', '🤝', '🚶', '💰', '🍓', '💢', '🤟', '🙁', '🚨', '💨',
'🤬', '✈', '🎀', '🍺', '🤓', '😙', '💟', '🌱', '😖', '👶',
'🥴', '▶', '➡', '❓', '💎', '💸', '⬇', '😨', '🌚', '🦋',
'😷', '🕺', '⚠', '🙅', '😟', '😵', '👎', '🤲', '🤠', '🤧',
'📌', '🔵', '💅', '🧐', '🐾', '🍒', '😗', '🤑', '🌊', '🤯',
'🐷', '☎', '💧', '😯', '💆', '👆', '🎤', '🙇', '🍑', '❄',
'🌴', '💣', '🐸', '💌', '📍', '🥀', '🤢', '👅', '💡', '💩',
'👐', '📸', '👻', '🤐', '🤮', '🎼', '🥵', '🚩', '🍎', '🍊',
'👼', '💍', '📣', '🥂',
}
var base256emojiReverseTable map[rune]byte
func init() {
base256emojiReverseTable = make(map[rune]byte, len(base256emojiTable))
for i, v := range base256emojiTable {
base256emojiReverseTable[v] = byte(i)
}
}
func base256emojiEncode(in []byte) string {
var l int
for _, v := range in {
l += utf8.RuneLen(base256emojiTable[v])
}
var out strings.Builder
out.Grow(l)
for _, v := range in {
out.WriteRune(base256emojiTable[v])
}
return out.String()
}
type base256emojiCorruptInputError struct {
index int
char rune
}
func (e base256emojiCorruptInputError) Error() string {
return "illegal base256emoji data at input byte " + strconv.FormatInt(int64(e.index), 10) + ", char: '" + string(e.char) + "'"
}
func (e base256emojiCorruptInputError) String() string {
return e.Error()
}
func base256emojiDecode(in string) ([]byte, error) {
out := make([]byte, utf8.RuneCountInString(in))
var stri int
for i := 0; len(in) > 0; i++ {
r, n := utf8.DecodeRuneInString(in)
in = in[n:]
var ok bool
out[i], ok = base256emojiReverseTable[r]
if !ok {
return nil, base256emojiCorruptInputError{stri, r}
}
stri += n
}
return out, nil
}

17
vendor/github.com/multiformats/go-multibase/base32.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
package multibase
import (
b32 "github.com/multiformats/go-base32"
)
var base32StdLowerPad = b32.NewEncodingCI("abcdefghijklmnopqrstuvwxyz234567")
var base32StdLowerNoPad = base32StdLowerPad.WithPadding(b32.NoPadding)
var base32StdUpperPad = b32.NewEncodingCI("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567")
var base32StdUpperNoPad = base32StdUpperPad.WithPadding(b32.NoPadding)
var base32HexLowerPad = b32.NewEncodingCI("0123456789abcdefghijklmnopqrstuv")
var base32HexLowerNoPad = base32HexLowerPad.WithPadding(b32.NoPadding)
var base32HexUpperPad = b32.NewEncodingCI("0123456789ABCDEFGHIJKLMNOPQRSTUV")
var base32HexUpperNoPad = base32HexUpperPad.WithPadding(b32.NoPadding)

65
vendor/github.com/multiformats/go-multibase/encoder.go generated vendored Normal file
View File

@@ -0,0 +1,65 @@
package multibase
import (
"fmt"
"unicode/utf8"
)
// Encoder is a multibase encoding that is verified to be supported and
// supports an Encode method that does not return an error
type Encoder struct {
enc Encoding
}
// NewEncoder create a new Encoder from an Encoding
func NewEncoder(base Encoding) (Encoder, error) {
_, ok := EncodingToStr[base]
if !ok {
return Encoder{-1}, fmt.Errorf("unsupported multibase encoding: %d", base)
}
return Encoder{base}, nil
}
// MustNewEncoder is like NewEncoder but will panic if the encoding is
// invalid.
func MustNewEncoder(base Encoding) Encoder {
_, ok := EncodingToStr[base]
if !ok {
panic("Unsupported multibase encoding")
}
return Encoder{base}
}
// EncoderByName creates an encoder from a string, the string can
// either be the multibase name or single character multibase prefix
func EncoderByName(str string) (Encoder, error) {
var base Encoding
var ok bool
if len(str) == 0 {
return Encoder{-1}, fmt.Errorf("empty multibase encoding")
} else if utf8.RuneCountInString(str) == 1 {
r, _ := utf8.DecodeRuneInString(str)
base = Encoding(r)
_, ok = EncodingToStr[base]
} else {
base, ok = Encodings[str]
}
if !ok {
return Encoder{-1}, fmt.Errorf("unsupported multibase encoding: %s", str)
}
return Encoder{base}, nil
}
func (p Encoder) Encoding() Encoding {
return p.enc
}
// Encode encodes the multibase using the given Encoder.
func (p Encoder) Encode(data []byte) string {
str, err := Encode(p.enc, data)
if err != nil {
// should not happen
panic(err)
}
return str
}

View File

@@ -0,0 +1,194 @@
package multibase
import (
"encoding/base64"
"encoding/hex"
"fmt"
"unicode/utf8"
b58 "github.com/mr-tron/base58/base58"
b32 "github.com/multiformats/go-base32"
b36 "github.com/multiformats/go-base36"
)
// Encoding identifies the type of base-encoding that a multibase is carrying.
type Encoding int
// These are the encodings specified in the standard, not are all
// supported yet
const (
Identity = 0x00
Base2 = '0'
Base8 = '7'
Base10 = '9'
Base16 = 'f'
Base16Upper = 'F'
Base32 = 'b'
Base32Upper = 'B'
Base32pad = 'c'
Base32padUpper = 'C'
Base32hex = 'v'
Base32hexUpper = 'V'
Base32hexPad = 't'
Base32hexPadUpper = 'T'
Base36 = 'k'
Base36Upper = 'K'
Base58BTC = 'z'
Base58Flickr = 'Z'
Base64 = 'm'
Base64url = 'u'
Base64pad = 'M'
Base64urlPad = 'U'
Base256Emoji = '🚀'
)
// EncodingToStr is a map of the supported encoding, unsupported encoding
// specified in standard are left out
var EncodingToStr = map[Encoding]string{
0x00: "identity",
'0': "base2",
'f': "base16",
'F': "base16upper",
'b': "base32",
'B': "base32upper",
'c': "base32pad",
'C': "base32padupper",
'v': "base32hex",
'V': "base32hexupper",
't': "base32hexpad",
'T': "base32hexpadupper",
'k': "base36",
'K': "base36upper",
'z': "base58btc",
'Z': "base58flickr",
'm': "base64",
'u': "base64url",
'M': "base64pad",
'U': "base64urlpad",
Base256Emoji: "base256emoji",
}
var Encodings = map[string]Encoding{}
func init() {
for e, n := range EncodingToStr {
Encodings[n] = e
}
}
// ErrUnsupportedEncoding is returned when the selected encoding is not known or
// implemented.
var ErrUnsupportedEncoding = fmt.Errorf("selected encoding not supported")
// Encode encodes a given byte slice with the selected encoding and returns a
// multibase string (<encoding><base-encoded-string>). It will return
// an error if the selected base is not known.
func Encode(base Encoding, data []byte) (string, error) {
switch base {
case Identity:
// 0x00 inside a string is OK in golang and causes no problems with the length calculation.
return string(rune(Identity)) + string(data), nil
case Base2:
return string(Base2) + binaryEncodeToString(data), nil
case Base16:
return string(Base16) + hex.EncodeToString(data), nil
case Base16Upper:
return string(Base16Upper) + hexEncodeToStringUpper(data), nil
case Base32:
return string(Base32) + base32StdLowerNoPad.EncodeToString(data), nil
case Base32Upper:
return string(Base32Upper) + base32StdUpperNoPad.EncodeToString(data), nil
case Base32hex:
return string(Base32hex) + base32HexLowerNoPad.EncodeToString(data), nil
case Base32hexUpper:
return string(Base32hexUpper) + base32HexUpperNoPad.EncodeToString(data), nil
case Base32pad:
return string(Base32pad) + base32StdLowerPad.EncodeToString(data), nil
case Base32padUpper:
return string(Base32padUpper) + base32StdUpperPad.EncodeToString(data), nil
case Base32hexPad:
return string(Base32hexPad) + base32HexLowerPad.EncodeToString(data), nil
case Base32hexPadUpper:
return string(Base32hexPadUpper) + base32HexUpperPad.EncodeToString(data), nil
case Base36:
return string(Base36) + b36.EncodeToStringLc(data), nil
case Base36Upper:
return string(Base36Upper) + b36.EncodeToStringUc(data), nil
case Base58BTC:
return string(Base58BTC) + b58.EncodeAlphabet(data, b58.BTCAlphabet), nil
case Base58Flickr:
return string(Base58Flickr) + b58.EncodeAlphabet(data, b58.FlickrAlphabet), nil
case Base64pad:
return string(Base64pad) + base64.StdEncoding.EncodeToString(data), nil
case Base64urlPad:
return string(Base64urlPad) + base64.URLEncoding.EncodeToString(data), nil
case Base64url:
return string(Base64url) + base64.RawURLEncoding.EncodeToString(data), nil
case Base64:
return string(Base64) + base64.RawStdEncoding.EncodeToString(data), nil
case Base256Emoji:
return string(Base256Emoji) + base256emojiEncode(data), nil
default:
return "", ErrUnsupportedEncoding
}
}
// Decode takes a multibase string and decodes into a bytes buffer.
// It will return an error if the selected base is not known.
func Decode(data string) (Encoding, []byte, error) {
if len(data) == 0 {
return 0, nil, fmt.Errorf("cannot decode multibase for zero length string")
}
r, _ := utf8.DecodeRuneInString(data)
enc := Encoding(r)
switch enc {
case Identity:
return Identity, []byte(data[1:]), nil
case Base2:
bytes, err := decodeBinaryString(data[1:])
return enc, bytes, err
case Base16, Base16Upper:
bytes, err := hex.DecodeString(data[1:])
return enc, bytes, err
case Base32, Base32Upper:
bytes, err := b32.RawStdEncoding.DecodeString(data[1:])
return enc, bytes, err
case Base32hex, Base32hexUpper:
bytes, err := b32.RawHexEncoding.DecodeString(data[1:])
return enc, bytes, err
case Base32pad, Base32padUpper:
bytes, err := b32.StdEncoding.DecodeString(data[1:])
return enc, bytes, err
case Base32hexPad, Base32hexPadUpper:
bytes, err := b32.HexEncoding.DecodeString(data[1:])
return enc, bytes, err
case Base36, Base36Upper:
bytes, err := b36.DecodeString(data[1:])
return enc, bytes, err
case Base58BTC:
bytes, err := b58.DecodeAlphabet(data[1:], b58.BTCAlphabet)
return Base58BTC, bytes, err
case Base58Flickr:
bytes, err := b58.DecodeAlphabet(data[1:], b58.FlickrAlphabet)
return Base58Flickr, bytes, err
case Base64pad:
bytes, err := base64.StdEncoding.DecodeString(data[1:])
return Base64pad, bytes, err
case Base64urlPad:
bytes, err := base64.URLEncoding.DecodeString(data[1:])
return Base64urlPad, bytes, err
case Base64:
bytes, err := base64.RawStdEncoding.DecodeString(data[1:])
return Base64, bytes, err
case Base64url:
bytes, err := base64.RawURLEncoding.DecodeString(data[1:])
return Base64url, bytes, err
case Base256Emoji:
bytes, err := base256emojiDecode(data[4:])
return Base256Emoji, bytes, err
default:
return -1, nil, ErrUnsupportedEncoding
}
}

View File

@@ -0,0 +1,10 @@
{
"author": "whyrusleeping",
"bugs": {
"url": "https://github.com/multiformats/go-multibase"
},
"language": "go",
"license": "",
"name": "go-multibase",
"version": "0.3.0"
}

View File

@@ -0,0 +1,3 @@
{
"version": "v0.2.0"
}

View File

@@ -0,0 +1,3 @@
[submodule "multicodec"]
path = multicodec
url = https://github.com/multiformats/multicodec

14
vendor/github.com/multiformats/go-multicodec/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,14 @@
This library is dual-licensed under either of Apache 2.0 or MIT terms:
- Apache-2.0 Software License: https://www.apache.org/licenses/LICENSE-2.0
- MIT Software License: https://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software
distributed under the terms listed in this notice is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied. See each License for the specific language
governing permissions and limitations under that License.
<!--- SPDX-License-Identifier: Apache-2.0 OR MIT -->
`SPDX-License-Identifier: Apache-2.0 OR MIT`

View File

@@ -0,0 +1,7 @@
Copyright (c) 2020 The Contributors
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2020 The Contributors
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.

109
vendor/github.com/multiformats/go-multicodec/README.md generated vendored Normal file
View File

@@ -0,0 +1,109 @@
# go-multicodec
[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg)](https://github.com/RichardLitt/standard-readme)
> Generated Go constants for the [multicodec table](https://github.com/multiformats/multicodec) used by the [multiformats](https://github.com/multiformats/multiformats) projects.
## Table of Contents
- [Install](#install)
- [Type](#type)
- [Usage](#usage)
- [Importing Code constant](#importing-code-constant)
- [Code from string](#code-from-string)
- [Code from uint64](#code-from-uint64)
- [Generator](#generator)
- [With old table.csv](#with-old-tablecsv)
- [With updated table.csv](#with-updated-tablecsv)
- [Maintainers](#maintainers)
- [Contribute](#contribute)
- [License](#license)
## Install
`go-multicodec` is a standard Go module:
go get github.com/multiformats/go-multicodec
## Type
`Code` describes an integer reserved in the multicodec table, defined at [multiformats/multicodec/table.csv](https://github.com/multiformats/multicodec/blob/master/table.csv).
```go
type Code uint64
```
## Usage
### Importing Code constant
```go
package main
import "github.com/multiformats/go-multicodec"
func main() {
code := multicodec.Sha2_256 // Code
name := multicodec.Sha2_256.String()
}
```
The corresponding `name` value for each codec from the [multicodecs table](https://raw.githubusercontent.com/multiformats/multicodec/master/table.csv) can be accessed via its `String` method. For example, `multicodec.Sha2_256.String()` will return `sha2-256`.
### Code from string
```go
var multicodec.Code code
err := code.Set("libp2p-key")
```
### Code from uint64
```go
rawCode := multicodec.Code(0x55)
```
## Generator
### With old table.csv
To generate the constants yourself:
```console
$ git clone https://github.com/multiformats/go-multicodec
$ cd go-multicodec
$ git submodule init && git submodule update
$ go generate
```
Note: You may need to install `stringer` via `go install golang.org/x/tools/cmd/stringer`.
### With updated table.csv
To generate the constants for the latest [table.csv](https://github.com/multiformats/multicodec/blob/master/table.csv):
```console
$ git clone https://github.com/multiformats/go-multicodec
$ cd go-multicodec
$ git submodule init
$ git submodule update --remote # updates ./multicodec/table.csv to upstream version
$ go generate
```
## Maintainers
[@mvdan](https://github.com/mvdan).
## Contribute
Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multicodec/issues).
Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
## License
SPDX-License-Identifier: Apache-2.0 OR MIT

88
vendor/github.com/multiformats/go-multicodec/code.go generated vendored Normal file
View File

@@ -0,0 +1,88 @@
// Package multicodec exposes the multicodec table as Go constants.
package multicodec
import (
"flag"
"fmt"
"strconv"
)
//go:generate go run gen.go
//go:generate gofmt -w code_table.go
//go:generate go run golang.org/x/tools/cmd/stringer@v0.5.0 -type=Code -linecomment
// Code describes an integer reserved in the multicodec table, defined at
// github.com/multiformats/multicodec.
type Code uint64
// Assert that Code implements flag.Value.
// Requires a pointer, since Set modifies the receiver.
//
// Note that we don't implement encoding.TextMarshaler and encoding.TextUnmarshaler.
// That's on purpose; even though multicodec names are stable just like the codes,
// Go should still generally encode and decode multicodecs by their code number.
// Many encoding libraries like xml and json default to TextMarshaler if it exists.
//
// Conversely, implementing flag.Value makes sense;
// --someflag=sha1 is useful as it would often be typed by a human.
var _ flag.Value = (*Code)(nil)
// Assert that Code implements fmt.Stringer without a pointer.
var _ fmt.Stringer = Code(0)
// ReservedStart is the (inclusive) start of the reserved range of codes that
// are safe to use for internal purposes.
const ReservedStart = 0x300000
// ReservedEnd is the (inclusive) end of the reserved range of codes that are
// safe to use for internal purposes.
const ReservedEnd = 0x3FFFFF
// Set implements flag.Value, interpreting the input string as a multicodec and
// setting the receiver to it.
//
// The input string can be the name or number for a known code. A number can be
// in any format accepted by strconv.ParseUint with base 0, including decimal
// and hexadecimal.
//
// Numbers in the reserved range 0x300000-0x3FFFFF are also accepted.
func (c *Code) Set(text string) error {
// Checking if the text is a valid number is cheap, so do it first.
// It should be impossible for a string to be both a valid number and a
// valid name, anyway.
if n, err := strconv.ParseUint(text, 0, 64); err == nil {
code := Code(n)
if code >= 0x300000 && code <= 0x3FFFFF { // reserved range
*c = code
return nil
}
if _, ok := _Code_map[code]; ok { // known code
*c = code
return nil
}
}
// For now, checking if the text is a valid name is a linear operation,
// so do it after.
// Right now we have ~450 codes, so a linear search isn't too bad.
// Consider generating a map[string]Code later on if linear search
// starts being a problem.
for code, name := range _Code_map {
if name == text {
*c = code
return nil
}
}
return fmt.Errorf("unknown multicodec: %q", text)
}
// Note that KnownCodes is a function backed by a code-generated slice.
// Later on, if the slice gets too large, we could codegen a packed form
// and only expand to a regular slice via a sync.Once.
// A function also makes it a bit clearer that the list should be read-only.
// KnownCodes returns a list of all codes registered in the multicodec table.
// The returned slice should be treated as read-only.
func KnownCodes() []Code {
return knownCodes
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
{
"version": "v0.9.0"
}

View File

@@ -0,0 +1 @@
.vscode/

View File

@@ -0,0 +1,6 @@
[submodule "spec/multicodec"]
path = spec/multicodec
url = https://github.com/multiformats/multicodec.git
[submodule "spec/multihash"]
path = spec/multihash
url = https://github.com/multiformats/multihash.git

21
vendor/github.com/multiformats/go-multihash/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Juan Batiz-Benet
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.

90
vendor/github.com/multiformats/go-multihash/README.md generated vendored Normal file
View File

@@ -0,0 +1,90 @@
# go-multihash
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs)
[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
[![GoDoc](https://godoc.org/github.com/multiformats/go-multihash?status.svg)](https://godoc.org/github.com/multiformats/go-multihash)
[![Travis CI](https://img.shields.io/travis/multiformats/go-multihash.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-multihash)
[![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-multihash.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-multihash?branch=master)
> [multihash](https://github.com/multiformats/multihash) implementation in Go
## Table of Contents
- [Install](#install)
- [Usage](#usage)
- [Maintainers](#maintainers)
- [Contribute](#contribute)
- [License](#license)
## Install
`go-multihash` is a standard Go module which can be installed with:
```sh
go get github.com/multiformats/go-multihash
```
## Usage
### Example
This example takes a standard hex-encoded data and uses `EncodeName` to calculate the SHA1 multihash value for the buffer.
The resulting hex-encoded data corresponds to: `<hash function code><digest size><hash function output>`, which could be re-parsed
with `Multihash.FromHexString()`.
```go
package main
import (
"encoding/hex"
"fmt"
"github.com/multiformats/go-multihash"
)
func main() {
// ignores errors for simplicity.
// don't do that at home.
// Decode a SHA1 hash to a binary buffer
buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
// Create a new multihash with it.
mHashBuf, _ := multihash.EncodeName(buf, "sha1")
// Print the multihash as hex string
fmt.Printf("hex: %s\n", hex.EncodeToString(mHashBuf))
// Parse the binary multihash to a DecodedMultihash
mHash, _ := multihash.Decode(mHashBuf)
// Convert the sha1 value to hex string
sha1hex := hex.EncodeToString(mHash.Digest)
// Print all the information in the multihash
fmt.Printf("obj: %v 0x%x %d %s\n", mHash.Name, mHash.Code, mHash.Length, sha1hex)
}
```
To run, copy to [example/foo.go](example/foo.go) and:
```
> cd example/
> go build
> ./example
hex: 11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
obj: sha1 0x11 20 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
```
## Contribute
Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multihash/issues).
Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
## License
[MIT](LICENSE) © 2014 Juan Batiz-Benet

View File

@@ -0,0 +1,3 @@
coverage:
range: "50...100"
comment: off

View File

@@ -0,0 +1,34 @@
package multihash
import (
"bytes"
"crypto/sha256"
"hash"
)
type identityMultihash struct {
bytes.Buffer
}
func (identityMultihash) BlockSize() int {
return 32 // A prefered block size is nonsense for the "identity" "hash". An arbitrary but unsurprising and positive nonzero number has been chosen to minimize the odds of fascinating bugs.
}
func (x *identityMultihash) Size() int {
return x.Len()
}
func (x *identityMultihash) Sum(digest []byte) []byte {
return x.Bytes()
}
type doubleSha256 struct {
hash.Hash
}
func (x doubleSha256) Sum(digest []byte) []byte {
digest = x.Hash.Sum(digest)
h2 := sha256.New()
h2.Write(digest)
return h2.Sum(digest[0:0])
}

View File

@@ -0,0 +1,35 @@
package multihash
import "errors"
// ErrSumNotSupported is returned when the Sum function code is not implemented
var ErrSumNotSupported = errors.New("no such hash registered")
// ErrLenTooLarge is returned when the hash function cannot produce the requested number of bytes
var ErrLenTooLarge = errors.New("requested length was too large for digest")
// constants
const (
IDENTITY = 0x00
SHA1 = 0x11
SHA2_224 = 0x1013
SHA2_256 = 0x12
SHA2_384 = 0x20
SHA2_512 = 0x13
SHA2_512_224 = 0x1014
SHA2_512_256 = 0x1015
SHA3_224 = 0x17
SHA3_256 = 0x16
SHA3_384 = 0x15
SHA3_512 = 0x14
KECCAK_224 = 0x1A
KECCAK_256 = 0x1B
KECCAK_384 = 0x1C
KECCAK_512 = 0x1D
BLAKE3 = 0x1E
SHAKE_128 = 0x18
SHAKE_256 = 0x19
MURMUR3X64_64 = 0x22
MD5 = 0xd5
DBL_SHA2_256 = 0x56
)

View File

@@ -0,0 +1,123 @@
package multihash
import (
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"fmt"
"hash"
)
// registry is a simple map which maps a multihash indicator number
// to a function : (size:int) -> ((hasher:hash.Hash), (bool:success))
// The function may error (i.e., return (nil, false)) to signify that the hasher can't return that many bytes.
//
// Multihash indicator numbers are reserved and described in
// https://github.com/multiformats/multicodec/blob/master/table.csv .
// The keys used in this map must match those reservations.
//
// Hashers which are available in the golang stdlib will be registered automatically.
// Others can be added using the Register function.
var registry = make(map[uint64]func(int) (h hash.Hash, ok bool))
// Register adds a new hash to the set available from GetHasher and Sum.
//
// Register has a global effect and should only be used at package init time to avoid data races.
//
// The indicator code should be per the numbers reserved and described in
// https://github.com/multiformats/multicodec/blob/master/table.csv .
//
// If Register is called with the same indicator code more than once, the last call wins.
// In practice, this means that if an application has a strong opinion about what implementation to use for a certain hash
// (e.g., perhaps they want to override the sha256 implementation to use a special hand-rolled assembly variant
// rather than the stdlib one which is registered by default),
// then this can be done by making a Register call with that effect at init time in the application's main package.
// This should have the desired effect because the root of the import tree has its init time effect last.
func Register(indicator uint64, hasherFactory func() hash.Hash) {
if hasherFactory == nil {
panic("not sensible to attempt to register a nil function")
}
maxSize := hasherFactory().Size()
registry[indicator] = func(size int) (hash.Hash, bool) {
if size > maxSize {
return nil, false
}
return hasherFactory(), true
}
DefaultLengths[indicator] = maxSize
}
// RegisterVariableSize is like Register, but adds a new variable-sized hasher factory that takes a
// size hint.
//
// When passed -1, the hasher should produce digests with the hash-function's default length. When
// passed a non-negative integer, the hasher should try to produce digests of at least the specified
// size.
func RegisterVariableSize(indicator uint64, hasherFactory func(sizeHint int) (hash.Hash, bool)) {
if hasherFactory == nil {
panic("not sensible to attempt to register a nil function")
}
if hasher, ok := hasherFactory(-1); !ok {
panic("failed to determine default hash length for hasher")
} else {
DefaultLengths[indicator] = hasher.Size()
}
registry[indicator] = hasherFactory
}
// GetHasher returns a new hash.Hash according to the indicator code number provided.
//
// The indicator code should be per the numbers reserved and described in
// https://github.com/multiformats/multicodec/blob/master/table.csv .
//
// The actual hashers available are determined by what has been registered.
// The registry automatically contains those hashers which are available in the golang standard libraries
// (which includes md5, sha1, sha256, sha384, sha512, and the "identity" mulithash, among others).
// Other hash implementations can be made available by using the Register function.
// The 'go-mulithash/register/*' packages can also be imported to gain more common hash functions.
//
// If an error is returned, it will match `errors.Is(err, ErrSumNotSupported)`.
func GetHasher(indicator uint64) (hash.Hash, error) {
return GetVariableHasher(indicator, -1)
}
// GetVariableHasher returns a new hash.Hash according to the indicator code number provided, with
// the specified size hint.
//
// NOTE: The size hint is only a hint. Hashers will attempt to produce at least the number of requested bytes, but may not.
//
// This function can fail if either the hash code is not registered, or the passed size hint is
// statically incompatible with the specified hash function.
func GetVariableHasher(indicator uint64, sizeHint int) (hash.Hash, error) {
factory, exists := registry[indicator]
if !exists {
return nil, fmt.Errorf("unknown multihash code %d (0x%x): %w", indicator, indicator, ErrSumNotSupported)
}
hasher, ok := factory(sizeHint)
if !ok {
return nil, ErrLenTooLarge
}
return hasher, nil
}
// DefaultLengths maps a multihash indicator code to the output size for that hash, in units of bytes.
//
// This map is populated when a hash function is registered by the Register function.
// It's effectively a shortcut for asking Size() on the hash.Hash.
var DefaultLengths = map[uint64]int{}
func init() {
RegisterVariableSize(IDENTITY, func(_ int) (hash.Hash, bool) { return &identityMultihash{}, true })
Register(MD5, md5.New)
Register(SHA1, sha1.New)
Register(SHA2_224, sha256.New224)
Register(SHA2_256, sha256.New)
Register(SHA2_384, sha512.New384)
Register(SHA2_512, sha512.New)
Register(SHA2_512_224, sha512.New512_224)
Register(SHA2_512_256, sha512.New512_256)
Register(DBL_SHA2_256, func() hash.Hash { return &doubleSha256{sha256.New()} })
}

98
vendor/github.com/multiformats/go-multihash/io.go generated vendored Normal file
View File

@@ -0,0 +1,98 @@
package multihash
import (
"errors"
"io"
"math"
"github.com/multiformats/go-varint"
)
// Reader is an io.Reader wrapper that exposes a function
// to read a whole multihash, parse it, and return it.
type Reader interface {
io.Reader
ReadMultihash() (Multihash, error)
}
// Writer is an io.Writer wrapper that exposes a function
// to write a whole multihash.
type Writer interface {
io.Writer
WriteMultihash(Multihash) error
}
// NewReader wraps an io.Reader with a multihash.Reader
func NewReader(r io.Reader) Reader {
return &mhReader{r}
}
// NewWriter wraps an io.Writer with a multihash.Writer
func NewWriter(w io.Writer) Writer {
return &mhWriter{w}
}
type mhReader struct {
r io.Reader
}
func (r *mhReader) Read(buf []byte) (n int, err error) {
return r.r.Read(buf)
}
func (r *mhReader) ReadByte() (byte, error) {
if br, ok := r.r.(io.ByteReader); ok {
return br.ReadByte()
}
var b [1]byte
n, err := r.r.Read(b[:])
if n == 1 {
return b[0], nil
}
if err == nil {
if n != 0 {
panic("reader returned an invalid length")
}
err = io.ErrNoProgress
}
return 0, err
}
func (r *mhReader) ReadMultihash() (Multihash, error) {
code, err := varint.ReadUvarint(r)
if err != nil {
return nil, err
}
length, err := varint.ReadUvarint(r)
if err != nil {
return nil, err
}
if length > math.MaxInt32 {
return nil, errors.New("digest too long, supporting only <= 2^31-1")
}
buf := make([]byte, varint.UvarintSize(code)+varint.UvarintSize(length)+int(length))
n := varint.PutUvarint(buf, code)
n += varint.PutUvarint(buf[n:], length)
if _, err := io.ReadFull(r.r, buf[n:]); err != nil {
return nil, err
}
return Cast(buf)
}
type mhWriter struct {
w io.Writer
}
func (w *mhWriter) Write(buf []byte) (n int, err error) {
return w.w.Write(buf)
}
func (w *mhWriter) WriteMultihash(m Multihash) error {
_, err := w.w.Write([]byte(m))
return err
}

View File

@@ -0,0 +1,322 @@
// Package multihash is the Go implementation of
// https://github.com/multiformats/multihash, or self-describing
// hashes.
package multihash
import (
"encoding/hex"
"errors"
"fmt"
"math"
b58 "github.com/mr-tron/base58/base58"
"github.com/multiformats/go-varint"
)
// errors
var (
ErrUnknownCode = errors.New("unknown multihash code")
ErrTooShort = errors.New("multihash too short. must be >= 2 bytes")
ErrTooLong = errors.New("multihash too long. must be < 129 bytes")
ErrLenNotSupported = errors.New("multihash does not yet support digests longer than 127 bytes")
ErrInvalidMultihash = errors.New("input isn't valid multihash")
ErrVarintBufferShort = errors.New("uvarint: buffer too small")
ErrVarintTooLong = errors.New("uvarint: varint too big (max 64bit)")
)
// ErrInconsistentLen is returned when a decoded multihash has an inconsistent length
type ErrInconsistentLen struct {
dm DecodedMultihash
lengthFound int
}
func (e ErrInconsistentLen) Error() string {
return fmt.Sprintf("multihash length inconsistent: expected %d; got %d", e.dm.Length, e.lengthFound)
}
// constants
const (
IDENTITY = 0x00
// Deprecated: use IDENTITY
ID = IDENTITY
SHA1 = 0x11
SHA2_256 = 0x12
SHA2_512 = 0x13
SHA3_224 = 0x17
SHA3_256 = 0x16
SHA3_384 = 0x15
SHA3_512 = 0x14
SHA3 = SHA3_512
KECCAK_224 = 0x1A
KECCAK_256 = 0x1B
KECCAK_384 = 0x1C
KECCAK_512 = 0x1D
BLAKE3 = 0x1E
SHAKE_128 = 0x18
SHAKE_256 = 0x19
BLAKE2B_MIN = 0xb201
BLAKE2B_MAX = 0xb240
BLAKE2S_MIN = 0xb241
BLAKE2S_MAX = 0xb260
MD5 = 0xd5
DBL_SHA2_256 = 0x56
MURMUR3X64_64 = 0x22
// Deprecated: use MURMUR3X64_64
MURMUR3 = MURMUR3X64_64
SHA2_256_TRUNC254_PADDED = 0x1012
X11 = 0x1100
POSEIDON_BLS12_381_A1_FC1 = 0xb401
)
func init() {
// Add blake2b (64 codes)
for c := uint64(BLAKE2B_MIN); c <= BLAKE2B_MAX; c++ {
n := c - BLAKE2B_MIN + 1
name := fmt.Sprintf("blake2b-%d", n*8)
Names[name] = c
Codes[c] = name
}
// Add blake2s (32 codes)
for c := uint64(BLAKE2S_MIN); c <= BLAKE2S_MAX; c++ {
n := c - BLAKE2S_MIN + 1
name := fmt.Sprintf("blake2s-%d", n*8)
Names[name] = c
Codes[c] = name
}
}
// Names maps the name of a hash to the code
var Names = map[string]uint64{
"identity": IDENTITY,
"sha1": SHA1,
"sha2-256": SHA2_256,
"sha2-512": SHA2_512,
"sha3": SHA3_512,
"sha3-224": SHA3_224,
"sha3-256": SHA3_256,
"sha3-384": SHA3_384,
"sha3-512": SHA3_512,
"dbl-sha2-256": DBL_SHA2_256,
"murmur3-x64-64": MURMUR3X64_64,
"keccak-224": KECCAK_224,
"keccak-256": KECCAK_256,
"keccak-384": KECCAK_384,
"keccak-512": KECCAK_512,
"blake3": BLAKE3,
"shake-128": SHAKE_128,
"shake-256": SHAKE_256,
"sha2-256-trunc254-padded": SHA2_256_TRUNC254_PADDED,
"x11": X11,
"md5": MD5,
"poseidon-bls12_381-a2-fc1": POSEIDON_BLS12_381_A1_FC1,
}
// Codes maps a hash code to it's name
var Codes = map[uint64]string{
IDENTITY: "identity",
SHA1: "sha1",
SHA2_256: "sha2-256",
SHA2_512: "sha2-512",
SHA3_224: "sha3-224",
SHA3_256: "sha3-256",
SHA3_384: "sha3-384",
SHA3_512: "sha3-512",
DBL_SHA2_256: "dbl-sha2-256",
MURMUR3X64_64: "murmur3-x64-64",
KECCAK_224: "keccak-224",
KECCAK_256: "keccak-256",
KECCAK_384: "keccak-384",
KECCAK_512: "keccak-512",
BLAKE3: "blake3",
SHAKE_128: "shake-128",
SHAKE_256: "shake-256",
SHA2_256_TRUNC254_PADDED: "sha2-256-trunc254-padded",
X11: "x11",
POSEIDON_BLS12_381_A1_FC1: "poseidon-bls12_381-a2-fc1",
MD5: "md5",
}
// reads a varint from buf and returns bytes read.
func uvarint(buf []byte) (uint64, []byte, error) {
n, c, err := varint.FromUvarint(buf)
if err != nil {
return n, buf, err
}
if c == 0 {
return n, buf, ErrVarintBufferShort
} else if c < 0 {
return n, buf[-c:], ErrVarintTooLong
} else {
return n, buf[c:], nil
}
}
// DecodedMultihash represents a parsed multihash and allows
// easy access to the different parts of a multihash.
type DecodedMultihash struct {
Code uint64
Name string
Length int // Length is just int as it is type of len() opearator
Digest []byte // Digest holds the raw multihash bytes
}
// Multihash is byte slice with the following form:
// <hash function code><digest size><hash function output>.
// See the spec for more information.
type Multihash []byte
// HexString returns the hex-encoded representation of a multihash.
func (m Multihash) HexString() string {
return hex.EncodeToString([]byte(m))
}
// String is an alias to HexString().
func (m Multihash) String() string {
return m.HexString()
}
// FromHexString parses a hex-encoded multihash.
func FromHexString(s string) (Multihash, error) {
b, err := hex.DecodeString(s)
if err != nil {
return Multihash{}, err
}
return Cast(b)
}
// B58String returns the B58-encoded representation of a multihash.
func (m Multihash) B58String() string {
return b58.Encode([]byte(m))
}
// FromB58String parses a B58-encoded multihash.
func FromB58String(s string) (m Multihash, err error) {
b, err := b58.Decode(s)
if err != nil {
return Multihash{}, ErrInvalidMultihash
}
return Cast(b)
}
// Cast casts a buffer onto a multihash, and returns an error
// if it does not work.
func Cast(buf []byte) (Multihash, error) {
_, err := Decode(buf)
if err != nil {
return Multihash{}, err
}
return Multihash(buf), nil
}
// Decode parses multihash bytes into a DecodedMultihash.
func Decode(buf []byte) (*DecodedMultihash, error) {
// outline decode allowing the &dm expression to be inlined into the caller.
// This moves the heap allocation into the caller and if the caller doesn't
// leak dm the compiler will use a stack allocation instead.
// If you do not outline this &dm always heap allocate since the pointer is
// returned which cause a heap allocation because Decode's stack frame is
// about to disapear.
dm, err := decode(buf)
if err != nil {
return nil, err
}
return &dm, nil
}
func decode(buf []byte) (dm DecodedMultihash, err error) {
rlen, code, hdig, err := readMultihashFromBuf(buf)
if err != nil {
return DecodedMultihash{}, err
}
dm = DecodedMultihash{
Code: code,
Name: Codes[code],
Length: len(hdig),
Digest: hdig,
}
if len(buf) != rlen {
return dm, ErrInconsistentLen{dm, rlen}
}
return dm, nil
}
// Encode a hash digest along with the specified function code.
// Note: the length is derived from the length of the digest itself.
//
// The error return is legacy; it is always nil.
func Encode(buf []byte, code uint64) ([]byte, error) {
// FUTURE: this function always causes heap allocs... but when used, this value is almost always going to be appended to another buffer (either as part of CID creation, or etc) -- should this whole function be rethought and alternatives offered?
newBuf := make([]byte, varint.UvarintSize(code)+varint.UvarintSize(uint64(len(buf)))+len(buf))
n := varint.PutUvarint(newBuf, code)
n += varint.PutUvarint(newBuf[n:], uint64(len(buf)))
copy(newBuf[n:], buf)
return newBuf, nil
}
// EncodeName is like Encode() but providing a string name
// instead of a numeric code. See Names for allowed values.
func EncodeName(buf []byte, name string) ([]byte, error) {
return Encode(buf, Names[name])
}
// readMultihashFromBuf reads a multihash from the given buffer, returning the
// individual pieces of the multihash.
// Note: the returned digest is a slice over the passed in data and should be
// copied if the buffer will be reused
func readMultihashFromBuf(buf []byte) (int, uint64, []byte, error) {
initBufLength := len(buf)
if initBufLength < 2 {
return 0, 0, nil, ErrTooShort
}
var err error
var code, length uint64
code, buf, err = uvarint(buf)
if err != nil {
return 0, 0, nil, err
}
length, buf, err = uvarint(buf)
if err != nil {
return 0, 0, nil, err
}
if length > math.MaxInt32 {
return 0, 0, nil, errors.New("digest too long, supporting only <= 2^31-1")
}
if int(length) > len(buf) {
return 0, 0, nil, errors.New("length greater than remaining number of bytes in buffer")
}
// rlen is the advertised size of the CID
rlen := (initBufLength - len(buf)) + int(length)
return rlen, code, buf[:length], nil
}
// MHFromBytes reads a multihash from the given byte buffer, returning the
// number of bytes read as well as the multihash
func MHFromBytes(buf []byte) (int, Multihash, error) {
nr, _, _, err := readMultihashFromBuf(buf)
if err != nil {
return 0, nil, err
}
return nr, Multihash(buf[:nr]), nil
}

View File

@@ -0,0 +1,24 @@
/*
This package has no purpose except to perform registration of mulithashes.
It is meant to be used as a side-effecting import, e.g.
import (
_ "github.com/multiformats/go-multihash/register/all"
)
This package registers many multihashes at once.
Importing it will increase the size of your dependency tree significantly.
It's recommended that you import this package if you're building some
kind of data broker application, which may need to handle many different kinds of hashes;
if you're building an application which you know only handles a specific hash,
importing this package may bloat your builds unnecessarily.
*/
package all
import (
_ "github.com/multiformats/go-multihash/register/blake2"
_ "github.com/multiformats/go-multihash/register/blake3"
_ "github.com/multiformats/go-multihash/register/murmur3"
_ "github.com/multiformats/go-multihash/register/sha3"
)

View File

@@ -0,0 +1,55 @@
/*
This package has no purpose except to perform registration of multihashes.
It is meant to be used as a side-effecting import, e.g.
import (
_ "github.com/multiformats/go-multihash/register/blake2"
)
This package registers several multihashes for the blake2 family
(both the 's' and the 'b' variants, and in a variety of sizes).
*/
package blake2
import (
"hash"
"golang.org/x/crypto/blake2b"
"golang.org/x/crypto/blake2s"
multihash "github.com/multiformats/go-multihash/core"
)
const (
blake2b_min = 0xb201
blake2b_max = 0xb240
blake2s_min = 0xb241
blake2s_max = 0xb260
)
func init() {
// blake2s
// This package only enables support for 32byte (256 bit) blake2s.
multihash.Register(blake2s_min+31, func() hash.Hash {
h, err := blake2s.New256(nil)
if err != nil {
panic(err)
}
return h
})
// blake2b
// There's a whole range of these.
for c := uint64(blake2b_min); c <= blake2b_max; c++ {
size := int(c - blake2b_min + 1)
multihash.Register(c, func() hash.Hash {
hasher, err := blake2b.New(size, nil)
if err != nil {
panic(err)
}
return hasher
})
}
}

View File

@@ -0,0 +1,33 @@
/*
This package has no purpose except to register the blake3 hash function.
It is meant to be used as a side-effecting import, e.g.
import (
_ "github.com/multiformats/go-multihash/register/blake3"
)
*/
package blake3
import (
"hash"
"lukechampine.com/blake3"
multihash "github.com/multiformats/go-multihash/core"
)
const DefaultSize = 32
const MaxSize = 128
func init() {
multihash.RegisterVariableSize(multihash.BLAKE3, func(size int) (hash.Hash, bool) {
if size == -1 {
size = DefaultSize
} else if size > MaxSize || size <= 0 {
return nil, false
}
h := blake3.New(size, nil)
return h, true
})
}

View File

@@ -0,0 +1,22 @@
//go:build go1.21
// This package has no purpose except to perform registration of multihashes.
//
// It is meant to be used as a side-effecting import, e.g.
//
// import (
// _ "github.com/multiformats/go-multihash/register/miniosha256"
// )
//
// This package registers alternative implementations for sha2-256, using
// the github.com/minio/sha256-simd library for go1.20 and bellow. Go 1.21 and
// later fallback to [github.com/multiformats/go-multihash/register/sha256].
//
// Deprecated: please switch to [github.com/multiformats/go-multihash/register/sha256]
// as of go1.21 the go std has a SHANI implementation that is just as fast. See https://go.dev/issue/50543.
// This will be removed shortly after go1.22 is released.
package miniosha256
import (
_ "github.com/multiformats/go-multihash/register/sha256"
)

View File

@@ -0,0 +1,29 @@
//go:build !go1.21
// This package has no purpose except to perform registration of multihashes.
//
// It is meant to be used as a side-effecting import, e.g.
//
// import (
// _ "github.com/multiformats/go-multihash/register/miniosha256"
// )
//
// This package registers alternative implementations for sha2-256, using
// the github.com/minio/sha256-simd library for go1.20 and bellow. Go 1.21 and
// later fallback to [github.com/multiformats/go-multihash/register/sha256].
//
// Note if you are using go1.21 or above this package is deprecated in favor of
// [github.com/multiformats/go-multihash/register/sha256] because as of go1.21
// the go std has a SHANI implementation that is just as fast. See https://go.dev/issue/50543.
// This will be removed shortly after go1.22 is released.
package miniosha256
import (
"github.com/minio/sha256-simd"
multihash "github.com/multiformats/go-multihash/core"
)
func init() {
multihash.Register(multihash.SHA2_256, sha256.New)
}

View File

@@ -0,0 +1,40 @@
/*
This package has no purpose except to perform registration of multihashes.
It is meant to be used as a side-effecting import, e.g.
import (
_ "github.com/multiformats/go-multihash/register/murmur3"
)
This package registers multihashes for murmur3
*/
package murmur3
import (
"hash"
multihash "github.com/multiformats/go-multihash/core"
"github.com/spaolacci/murmur3"
)
func init() {
multihash.Register(multihash.MURMUR3X64_64, func() hash.Hash { return murmur64{murmur3.New64()} })
}
// A wrapper is needed to export the correct size, because murmur3 incorrectly advertises Hash64 as a 128bit hash.
type murmur64 struct {
hash.Hash64
}
func (murmur64) BlockSize() int {
return 1
}
func (x murmur64) Size() int {
return 8
}
func (x murmur64) Sum(digest []byte) []byte {
return x.Hash64.Sum(digest)
}

View File

@@ -0,0 +1,21 @@
// This package has no purpose except to perform registration of multihashes.
//
// It is meant to be used as a side-effecting import, e.g.
//
// import (
// _ "github.com/multiformats/go-multihash/register/sha256"
// )
//
// This package an implementation of sha256 using the go std, this is recomanded
// if you are using go1.21 or above.
package sha256
import (
"crypto/sha256"
multihash "github.com/multiformats/go-multihash/core"
)
func init() {
multihash.Register(multihash.SHA2_256, sha256.New)
}

View File

@@ -0,0 +1,62 @@
/*
This package has no purpose except to perform registration of multihashes.
It is meant to be used as a side-effecting import, e.g.
import (
_ "github.com/multiformats/go-multihash/register/sha3"
)
This package registers several multihashes for the sha3 family.
This also includes some functions known as "shake" and "keccak",
since they share much of their implementation and come in the same repos.
*/
package sha3
import (
"hash"
"golang.org/x/crypto/sha3"
multihash "github.com/multiformats/go-multihash/core"
)
func init() {
multihash.Register(multihash.SHA3_512, sha3.New512)
multihash.Register(multihash.SHA3_384, sha3.New384)
multihash.Register(multihash.SHA3_256, sha3.New256)
multihash.Register(multihash.SHA3_224, sha3.New224)
multihash.Register(multihash.SHAKE_128, func() hash.Hash { return shakeNormalizer{sha3.NewShake128(), 128 / 8 * 2} })
multihash.Register(multihash.SHAKE_256, func() hash.Hash { return shakeNormalizer{sha3.NewShake256(), 256 / 8 * 2} })
multihash.Register(multihash.KECCAK_256, sha3.NewLegacyKeccak256)
multihash.Register(multihash.KECCAK_512, sha3.NewLegacyKeccak512)
}
// sha3.ShakeHash presents a somewhat odd interface, and requires a wrapper to normalize it to the usual hash.Hash interface.
//
// Some of the fiddly bits required by this normalization probably makes it undesirable for use in the highest performance applications;
// There's at least one extra allocation in constructing it (sha3.ShakeHash is an interface, so that's one heap escape; and there's a second heap escape when this normalizer struct gets boxed into a hash.Hash interface),
// and there's at least one extra allocation in getting a sum out of it (because reading a shake hash is a mutation (!) and the API only provides cloning as a way to escape this).
// Fun.
type shakeNormalizer struct {
sha3.ShakeHash
size int
}
func (shakeNormalizer) BlockSize() int {
return 32 // Shake doesn't have a prefered block size, apparently. An arbitrary but unsurprising and positive nonzero number has been chosen to minimize the odds of fascinating bugs.
}
func (x shakeNormalizer) Size() int {
return x.size
}
func (x shakeNormalizer) Sum(digest []byte) []byte {
if len(digest) < x.size {
digest = make([]byte, x.size)
}
digest = digest[0:x.size]
h2 := x.Clone() // clone it, because reading mutates this kind of hash (!) which is not the standard contract for a Hash.Sum method.
h2.Read(digest) // not capable of underreading. See sha3.ShakeSum256 for similar usage.
return digest
}

View File

@@ -0,0 +1,31 @@
package multihash
import (
"hash"
mhreg "github.com/multiformats/go-multihash/core"
_ "github.com/multiformats/go-multihash/register/all"
_ "github.com/multiformats/go-multihash/register/miniosha256"
)
// Register is an alias for Register in the core package.
//
// Consider using the core package instead of this multihash package;
// that package does not introduce transitive dependencies except for those you opt into,
// and will can result in smaller application builds.
func Register(indicator uint64, hasherFactory func() hash.Hash) {
mhreg.Register(indicator, hasherFactory)
}
// Register is an alias for Register in the core package.
//
// Consider using the core package instead of this multihash package;
// that package does not introduce transitive dependencies except for those you opt into,
// and will can result in smaller application builds.
func GetHasher(indicator uint64) (hash.Hash, error) {
return mhreg.GetHasher(indicator)
}
// DefaultLengths maps a multihash indicator code to the output size for that hash, in units of bytes.
var DefaultLengths = mhreg.DefaultLengths

66
vendor/github.com/multiformats/go-multihash/set.go generated vendored Normal file
View File

@@ -0,0 +1,66 @@
package multihash
// Set is a set of Multihashes, holding one copy per Multihash.
type Set struct {
set map[string]struct{}
}
// NewSet creates a new set correctly initialized.
func NewSet() *Set {
return &Set{
set: make(map[string]struct{}),
}
}
// Add adds a new multihash to the set.
func (s *Set) Add(m Multihash) {
s.set[string(m)] = struct{}{}
}
// Len returns the number of elements in the set.
func (s *Set) Len() int {
return len(s.set)
}
// Has returns true if the element is in the set.
func (s *Set) Has(m Multihash) bool {
_, ok := s.set[string(m)]
return ok
}
// Visit adds a multihash only if it is not in the set already. Returns true
// if the multihash was added (was not in the set before).
func (s *Set) Visit(m Multihash) bool {
_, ok := s.set[string(m)]
if !ok {
s.set[string(m)] = struct{}{}
return true
}
return false
}
// ForEach runs f(m) with each multihash in the set. If returns immediately if
// f(m) returns an error.
func (s *Set) ForEach(f func(m Multihash) error) error {
for elem := range s.set {
mh := Multihash(elem)
if err := f(mh); err != nil {
return err
}
}
return nil
}
// Remove removes an element from the set.
func (s *Set) Remove(m Multihash) {
delete(s.set, string(m))
}
// All returns a slice with all the elements in the set.
func (s *Set) All() []Multihash {
out := make([]Multihash, 0, len(s.set))
for m := range s.set {
out = append(out, Multihash(m))
}
return out
}

77
vendor/github.com/multiformats/go-multihash/sum.go generated vendored Normal file
View File

@@ -0,0 +1,77 @@
package multihash
import (
"fmt"
"hash"
"io"
mhreg "github.com/multiformats/go-multihash/core"
)
// ErrSumNotSupported is returned when the Sum function code is not implemented
var ErrSumNotSupported = mhreg.ErrSumNotSupported
var ErrLenTooLarge = mhreg.ErrLenTooLarge
// Sum obtains the cryptographic sum of a given buffer. The length parameter
// indicates the length of the resulting digest. Passing a negative value uses
// default length values for the selected hash function.
func Sum(data []byte, code uint64, length int) (Multihash, error) {
// Get the algorithm.
hasher, err := mhreg.GetVariableHasher(code, length)
if err != nil {
return nil, err
}
// Feed data in.
if _, err := hasher.Write(data); err != nil {
return nil, err
}
return encodeHash(hasher, code, length)
}
// SumStream obtains the cryptographic sum of a given stream. The length
// parameter indicates the length of the resulting digest. Passing a negative
// value uses default length values for the selected hash function.
func SumStream(r io.Reader, code uint64, length int) (Multihash, error) {
// Get the algorithm.
hasher, err := mhreg.GetVariableHasher(code, length)
if err != nil {
return nil, err
}
// Feed data in.
if _, err = io.Copy(hasher, r); err != nil {
return nil, err
}
return encodeHash(hasher, code, length)
}
func encodeHash(hasher hash.Hash, code uint64, length int) (Multihash, error) {
// Compute final hash.
// A new slice is allocated. FUTURE: see other comment below about allocation, and review together with this line to try to improve.
sum := hasher.Sum(nil)
// Deal with any truncation.
// Unless it's an identity multihash. Those have different rules.
if length < 0 {
length = hasher.Size()
}
if len(sum) < length {
return nil, ErrLenTooLarge
}
if length >= 0 {
if code == IDENTITY {
if length != len(sum) {
return nil, fmt.Errorf("the length of the identity hash (%d) must be equal to the length of the data (%d)", length, len(sum))
}
}
sum = sum[:length]
}
// Put the multihash metainfo bytes at the front of the buffer.
// FUTURE: try to improve allocations here. Encode does several which are probably avoidable, but it's the shape of the Encode method arguments that forces this.
return Encode(sum, code)
}

View File

@@ -0,0 +1,3 @@
{
"version": "v0.2.3"
}

21
vendor/github.com/multiformats/go-multistream/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Jeromy Johnson
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.

128
vendor/github.com/multiformats/go-multistream/README.md generated vendored Normal file
View File

@@ -0,0 +1,128 @@
# go-multistream
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs)
[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
[![GoDoc](https://godoc.org/github.com/multiformats/go-multistream?status.svg)](https://godoc.org/github.com/multiformats/go-multistream)
[![Travis CI](https://img.shields.io/travis/multiformats/go-multistream.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-multistream)
[![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-multistream.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-multistream?branch=master)
> an implementation of the multistream protocol in go
This package implements a simple stream router for the multistream-select protocol.
The protocol is defined [here](https://github.com/multiformats/multistream-select).
## Table of Contents
- [Install](#install)
- [Usage](#usage)
- [Maintainers](#maintainers)
- [Contribute](#contribute)
- [License](#license)
## Install
`go-multistream` is a standard Go module which can be installed with:
```sh
go get github.com/multiformats/go-multistream
```
## Usage
### Example
This example shows how to use a multistream muxer. A muxer uses user-added handlers to handle different "protocols". The first step when interacting with a connection handler by the muxer is to select the protocol (the example uses `SelectProtoOrFail`). This will then let the muxer use the right handler.
```go
package main
import (
"fmt"
"io"
"io/ioutil"
"net"
ms "github.com/multiformats/go-multistream"
)
// This example creates a multistream muxer, adds handlers for the protocols
// "/cats" and "/dogs" and exposes it on a localhost:8765. It then opens connections
// to that port, selects the protocols and tests that the handlers are working.
func main() {
mux := ms.NewMultistreamMuxer[string]()
mux.AddHandler("/cats", func(proto string, rwc io.ReadWriteCloser) error {
fmt.Fprintln(rwc, proto, ": HELLO I LIKE CATS")
return rwc.Close()
})
mux.AddHandler("/dogs", func(proto string, rwc io.ReadWriteCloser) error {
fmt.Fprintln(rwc, proto, ": HELLO I LIKE DOGS")
return rwc.Close()
})
list, err := net.Listen("tcp", ":8765")
if err != nil {
panic(err)
}
go func() {
for {
con, err := list.Accept()
if err != nil {
panic(err)
}
go mux.Handle(con)
}
}()
// The Muxer is ready, let's test it
conn, err := net.Dial("tcp", ":8765")
if err != nil {
panic(err)
}
// Create a new multistream to talk to the muxer
// which will negotiate that we want to talk with /cats
mstream := ms.NewMSSelect(conn, "/cats")
cats, err := ioutil.ReadAll(mstream)
if err != nil {
panic(err)
}
fmt.Printf("%s", cats)
mstream.Close()
// A different way of talking to the muxer
// is to manually selecting the protocol ourselves
conn, err = net.Dial("tcp", ":8765")
if err != nil {
panic(err)
}
defer conn.Close()
err = ms.SelectProtoOrFail("/dogs", conn)
if err != nil {
panic(err)
}
dogs, err := ioutil.ReadAll(conn)
if err != nil {
panic(err)
}
fmt.Printf("%s", dogs)
conn.Close()
}
```
## Contribute
Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multistream/issues).
Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
## License
[MIT](LICENSE) © 2016 Jeromy Johnson

151
vendor/github.com/multiformats/go-multistream/client.go generated vendored Normal file
View File

@@ -0,0 +1,151 @@
package multistream
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"runtime/debug"
)
// ErrNotSupported is the error returned when the muxer doesn't support
// the protocols tried for the handshake.
type ErrNotSupported[T StringLike] struct {
// Slice of protocols that were not supported by the muxer
Protos []T
}
func (e ErrNotSupported[T]) Error() string {
return fmt.Sprintf("protocols not supported: %v", e.Protos)
}
func (e ErrNotSupported[T]) Is(target error) bool {
_, ok := target.(ErrNotSupported[T])
return ok
}
// ErrNoProtocols is the error returned when the no protocols have been
// specified.
var ErrNoProtocols = errors.New("no protocols specified")
// SelectProtoOrFail performs the initial multistream handshake
// to inform the muxer of the protocol that will be used to communicate
// on this ReadWriteCloser. It returns an error if, for example,
// the muxer does not know how to handle this protocol.
func SelectProtoOrFail[T StringLike](proto T, rwc io.ReadWriteCloser) (err error) {
defer func() {
if rerr := recover(); rerr != nil {
fmt.Fprintf(os.Stderr, "caught panic: %s\n%s\n", rerr, debug.Stack())
err = fmt.Errorf("panic selecting protocol: %s", rerr)
}
}()
errCh := make(chan error, 1)
go func() {
var buf bytes.Buffer
if err := delitmWriteAll(&buf, []byte(ProtocolID), []byte(proto)); err != nil {
errCh <- err
return
}
_, err := io.Copy(rwc, &buf)
errCh <- err
}()
// We have to read *both* errors.
err1 := readMultistreamHeader(rwc)
err2 := readProto(proto, rwc)
if werr := <-errCh; werr != nil {
return werr
}
if err1 != nil {
return err1
}
if err2 != nil {
return err2
}
return nil
}
// SelectOneOf will perform handshakes with the protocols on the given slice
// until it finds one which is supported by the muxer.
func SelectOneOf[T StringLike](protos []T, rwc io.ReadWriteCloser) (proto T, err error) {
defer func() {
if rerr := recover(); rerr != nil {
fmt.Fprintf(os.Stderr, "caught panic: %s\n%s\n", rerr, debug.Stack())
err = fmt.Errorf("panic selecting one of protocols: %s", rerr)
}
}()
if len(protos) == 0 {
return "", ErrNoProtocols
}
// Use SelectProtoOrFail to pipeline the /multistream/1.0.0 handshake
// with an attempt to negotiate the first protocol. If that fails, we
// can continue negotiating the rest of the protocols normally.
//
// This saves us a round trip.
switch err := SelectProtoOrFail(protos[0], rwc); err.(type) {
case nil:
return protos[0], nil
case ErrNotSupported[T]: // try others
default:
return "", err
}
proto, err = selectProtosOrFail(protos[1:], rwc)
if _, ok := err.(ErrNotSupported[T]); ok {
return "", ErrNotSupported[T]{protos}
}
return proto, err
}
func selectProtosOrFail[T StringLike](protos []T, rwc io.ReadWriteCloser) (T, error) {
for _, p := range protos {
err := trySelect(p, rwc)
switch err := err.(type) {
case nil:
return p, nil
case ErrNotSupported[T]:
default:
return "", err
}
}
return "", ErrNotSupported[T]{protos}
}
func readMultistreamHeader(r io.Reader) error {
tok, err := ReadNextToken[string](r)
if err != nil {
return err
}
if tok != ProtocolID {
return errors.New("received mismatch in protocol id")
}
return nil
}
func trySelect[T StringLike](proto T, rwc io.ReadWriteCloser) error {
err := delimWriteBuffered(rwc, []byte(proto))
if err != nil {
return err
}
return readProto(proto, rwc)
}
func readProto[T StringLike](proto T, r io.Reader) error {
tok, err := ReadNextToken[T](r)
if err != nil {
return err
}
switch tok {
case proto:
return nil
case "na":
return ErrNotSupported[T]{[]T{proto}}
default:
return fmt.Errorf("unrecognized response: %s", tok)
}
}

View File

@@ -0,0 +1,160 @@
package multistream
import (
"fmt"
"io"
"sync"
)
// NewMSSelect returns a new Multistream which is able to perform
// protocol selection with a MultistreamMuxer.
func NewMSSelect[T StringLike](c io.ReadWriteCloser, proto T) LazyConn {
return &lazyClientConn[T]{
protos: []T{ProtocolID, proto},
con: c,
}
}
// NewMultistream returns a multistream for the given protocol. This will not
// perform any protocol selection. If you are using a MultistreamMuxer, use
// NewMSSelect.
func NewMultistream[T StringLike](c io.ReadWriteCloser, proto T) LazyConn {
return &lazyClientConn[T]{
protos: []T{proto},
con: c,
}
}
// lazyClientConn is a ReadWriteCloser adapter that lazily negotiates a protocol
// using multistream-select on first use.
//
// It *does not* block writes waiting for the other end to respond. Instead, it
// simply assumes the negotiation went successfully and starts writing data.
// See: https://github.com/multiformats/go-multistream/issues/20
type lazyClientConn[T StringLike] struct {
// Used to ensure we only trigger the write half of the handshake once.
rhandshakeOnce sync.Once
rerr error
// Used to ensure we only trigger the read half of the handshake once.
whandshakeOnce sync.Once
werr error
// The sequence of protocols to negotiate.
protos []T
// The inner connection.
con io.ReadWriteCloser
}
// Read reads data from the io.ReadWriteCloser.
//
// If the protocol hasn't yet been negotiated, this method triggers the write
// half of the handshake and then waits for the read half to complete.
//
// It returns an error if the read half of the handshake fails.
func (l *lazyClientConn[T]) Read(b []byte) (int, error) {
l.rhandshakeOnce.Do(func() {
go l.whandshakeOnce.Do(l.doWriteHandshake)
l.doReadHandshake()
})
if l.rerr != nil {
return 0, l.rerr
}
if len(b) == 0 {
return 0, nil
}
return l.con.Read(b)
}
func (l *lazyClientConn[T]) doReadHandshake() {
for _, proto := range l.protos {
// read protocol
tok, err := ReadNextToken[T](l.con)
if err != nil {
l.rerr = err
return
}
if tok == "na" {
l.rerr = ErrNotSupported[T]{[]T{proto}}
return
}
if tok != proto {
l.rerr = fmt.Errorf("protocol mismatch in lazy handshake ( %s != %s )", tok, proto)
return
}
}
}
func (l *lazyClientConn[T]) doWriteHandshake() {
l.doWriteHandshakeWithData(nil)
}
// Perform the write handshake but *also* write some extra data.
func (l *lazyClientConn[T]) doWriteHandshakeWithData(extra []byte) int {
buf := getWriter(l.con)
defer putWriter(buf)
for _, proto := range l.protos {
l.werr = delimWrite(buf, []byte(proto))
if l.werr != nil {
return 0
}
}
n := 0
if len(extra) > 0 {
n, l.werr = buf.Write(extra)
if l.werr != nil {
return n
}
}
l.werr = buf.Flush()
return n
}
// Write writes the given buffer to the underlying connection.
//
// If the protocol has not yet been negotiated, write waits for the write half
// of the handshake to complete triggers (but does not wait for) the read half.
//
// Write *also* ignores errors from the read half of the handshake (in case the
// stream is actually write only).
func (l *lazyClientConn[T]) Write(b []byte) (int, error) {
n := 0
l.whandshakeOnce.Do(func() {
go l.rhandshakeOnce.Do(l.doReadHandshake)
n = l.doWriteHandshakeWithData(b)
})
if l.werr != nil || n > 0 {
return n, l.werr
}
return l.con.Write(b)
}
// Close closes the underlying io.ReadWriteCloser
//
// This does not flush anything.
func (l *lazyClientConn[T]) Close() error {
// As the client, we flush the handshake on close to cover an
// interesting edge-case where the server only speaks a single protocol
// and responds eagerly with that protocol before waiting for out
// handshake.
//
// Again, we must not read the error because the other end may have
// closed the stream for reading. I mean, we're the initiator so that's
// strange... but it's still allowed
_ = l.Flush()
return l.con.Close()
}
// Flush sends the handshake.
func (l *lazyClientConn[T]) Flush() error {
l.whandshakeOnce.Do(func() {
go l.rhandshakeOnce.Do(l.doReadHandshake)
l.doWriteHandshake()
})
return l.werr
}

View File

@@ -0,0 +1,344 @@
// Package multistream implements a simple stream router for the
// multistream-select protocoli. The protocol is defined at
// https://github.com/multiformats/multistream-select
package multistream
import (
"bufio"
"errors"
"fmt"
"io"
"os"
"runtime/debug"
"sync"
"github.com/multiformats/go-varint"
)
// ErrTooLarge is an error to signal that an incoming message was too large
var ErrTooLarge = errors.New("incoming message was too large")
// ProtocolID identifies the multistream protocol itself and makes sure
// the multistream muxers on both sides of a channel can work with each other.
const ProtocolID = "/multistream/1.0.0"
var writerPool = sync.Pool{
New: func() interface{} {
return bufio.NewWriter(nil)
},
}
// StringLike is an interface that supports all types with underlying type
// string
type StringLike interface {
~string
}
// HandlerFunc is a user-provided function used by the MultistreamMuxer to
// handle a protocol/stream.
type HandlerFunc[T StringLike] func(protocol T, rwc io.ReadWriteCloser) error
// Handler is a wrapper to HandlerFunc which attaches a name (protocol) and a
// match function which can optionally be used to select a handler by other
// means than the name.
type Handler[T StringLike] struct {
MatchFunc func(T) bool
Handle HandlerFunc[T]
AddName T
}
// MultistreamMuxer is a muxer for multistream. Depending on the stream
// protocol tag it will select the right handler and hand the stream off to it.
type MultistreamMuxer[T StringLike] struct {
handlerlock sync.RWMutex
handlers []Handler[T]
}
// NewMultistreamMuxer creates a muxer.
func NewMultistreamMuxer[T StringLike]() *MultistreamMuxer[T] {
return new(MultistreamMuxer[T])
}
// LazyConn is the connection type returned by the lazy negotiation functions.
type LazyConn interface {
io.ReadWriteCloser
// Flush flushes the lazy negotiation, if any.
Flush() error
}
func writeUvarint(w io.Writer, i uint64) error {
varintbuf := make([]byte, 16)
n := varint.PutUvarint(varintbuf, i)
_, err := w.Write(varintbuf[:n])
if err != nil {
return err
}
return nil
}
func delimWriteBuffered(w io.Writer, mes []byte) error {
bw := getWriter(w)
defer putWriter(bw)
err := delimWrite(bw, mes)
if err != nil {
return err
}
return bw.Flush()
}
func delitmWriteAll(w io.Writer, messages ...[]byte) error {
for _, mes := range messages {
if err := delimWrite(w, mes); err != nil {
return fmt.Errorf("failed to write messages %s, err: %v ", string(mes), err)
}
}
return nil
}
func delimWrite(w io.Writer, mes []byte) error {
err := writeUvarint(w, uint64(len(mes)+1))
if err != nil {
return err
}
_, err = w.Write(mes)
if err != nil {
return err
}
_, err = w.Write([]byte{'\n'})
if err != nil {
return err
}
return nil
}
func fulltextMatch[T StringLike](s T) func(T) bool {
return func(a T) bool {
return a == s
}
}
// AddHandler attaches a new protocol handler to the muxer.
func (msm *MultistreamMuxer[T]) AddHandler(protocol T, handler HandlerFunc[T]) {
msm.AddHandlerWithFunc(protocol, fulltextMatch(protocol), handler)
}
// AddHandlerWithFunc attaches a new protocol handler to the muxer with a match.
// If the match function returns true for a given protocol tag, the protocol
// will be selected even if the handler name and protocol tags are different.
func (msm *MultistreamMuxer[T]) AddHandlerWithFunc(protocol T, match func(T) bool, handler HandlerFunc[T]) {
msm.handlerlock.Lock()
defer msm.handlerlock.Unlock()
msm.removeHandler(protocol)
msm.handlers = append(msm.handlers, Handler[T]{
MatchFunc: match,
Handle: handler,
AddName: protocol,
})
}
// RemoveHandler removes the handler with the given name from the muxer.
func (msm *MultistreamMuxer[T]) RemoveHandler(protocol T) {
msm.handlerlock.Lock()
defer msm.handlerlock.Unlock()
msm.removeHandler(protocol)
}
func (msm *MultistreamMuxer[T]) removeHandler(protocol T) {
for i, h := range msm.handlers {
if h.AddName == protocol {
msm.handlers = append(msm.handlers[:i], msm.handlers[i+1:]...)
return
}
}
}
// Protocols returns the list of handler-names added to this this muxer.
func (msm *MultistreamMuxer[T]) Protocols() []T {
msm.handlerlock.RLock()
defer msm.handlerlock.RUnlock()
var out []T
for _, h := range msm.handlers {
out = append(out, h.AddName)
}
return out
}
// ErrIncorrectVersion is an error reported when the muxer protocol negotiation
// fails because of a ProtocolID mismatch.
var ErrIncorrectVersion = errors.New("client connected with incorrect version")
func (msm *MultistreamMuxer[T]) findHandler(proto T) *Handler[T] {
msm.handlerlock.RLock()
defer msm.handlerlock.RUnlock()
for _, h := range msm.handlers {
if h.MatchFunc(proto) {
return &h
}
}
return nil
}
// Negotiate performs protocol selection and returns the protocol name and
// the matching handler function for it (or an error).
func (msm *MultistreamMuxer[T]) Negotiate(rwc io.ReadWriteCloser) (proto T, handler HandlerFunc[T], err error) {
defer func() {
if rerr := recover(); rerr != nil {
fmt.Fprintf(os.Stderr, "caught panic: %s\n%s\n", rerr, debug.Stack())
err = fmt.Errorf("panic in multistream negotiation: %s", rerr)
}
}()
// Send the multistream protocol ID
// Ignore the error here. We want the handshake to finish, even if the
// other side has closed this rwc for writing. They may have sent us a
// message and closed. Future writers will get an error anyways.
_ = delimWriteBuffered(rwc, []byte(ProtocolID))
line, err := ReadNextToken[T](rwc)
if err != nil {
return "", nil, err
}
if line != ProtocolID {
rwc.Close()
return "", nil, ErrIncorrectVersion
}
loop:
for {
// Now read and respond to commands until they send a valid protocol id
tok, err := ReadNextToken[T](rwc)
if err != nil {
return "", nil, err
}
h := msm.findHandler(tok)
if h == nil {
if err := delimWriteBuffered(rwc, []byte("na")); err != nil {
return "", nil, err
}
continue loop
}
// Ignore the error here. We want the handshake to finish, even if the
// other side has closed this rwc for writing. They may have sent us a
// message and closed. Future writers will get an error anyways.
_ = delimWriteBuffered(rwc, []byte(tok))
// hand off processing to the sub-protocol handler
return tok, h.Handle, nil
}
}
// Handle performs protocol negotiation on a ReadWriteCloser
// (i.e. a connection). It will find a matching handler for the
// incoming protocol and pass the ReadWriteCloser to it.
func (msm *MultistreamMuxer[T]) Handle(rwc io.ReadWriteCloser) error {
p, h, err := msm.Negotiate(rwc)
if err != nil {
return err
}
return h(p, rwc)
}
// ReadNextToken extracts a token from a Reader. It is used during
// protocol negotiation and returns a string.
func ReadNextToken[T StringLike](r io.Reader) (T, error) {
tok, err := ReadNextTokenBytes(r)
if err != nil {
return "", err
}
return T(tok), nil
}
// ReadNextTokenBytes extracts a token from a Reader. It is used
// during protocol negotiation and returns a byte slice.
func ReadNextTokenBytes(r io.Reader) ([]byte, error) {
data, err := lpReadBuf(r)
switch err {
case nil:
return data, nil
case ErrTooLarge:
return nil, ErrTooLarge
default:
return nil, err
}
}
func lpReadBuf(r io.Reader) ([]byte, error) {
br, ok := r.(io.ByteReader)
if !ok {
br = &byteReader{r}
}
length, err := varint.ReadUvarint(br)
if err != nil {
return nil, err
}
if length > 1024 {
return nil, ErrTooLarge
}
buf := make([]byte, length)
_, err = io.ReadFull(r, buf)
if err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return nil, err
}
if len(buf) == 0 || buf[length-1] != '\n' {
return nil, errors.New("message did not have trailing newline")
}
// slice off the trailing newline
buf = buf[:length-1]
return buf, nil
}
// byteReader implements the ByteReader interface that ReadUVarint requires
type byteReader struct {
io.Reader
}
func (br *byteReader) ReadByte() (byte, error) {
var b [1]byte
n, err := br.Read(b[:])
if n == 1 {
return b[0], nil
}
if err == nil {
if n != 0 {
panic("read more bytes than buffer size")
}
err = io.ErrNoProgress
}
return 0, err
}
func getWriter(w io.Writer) *bufio.Writer {
bw := writerPool.Get().(*bufio.Writer)
bw.Reset(w)
return bw
}
func putWriter(bw *bufio.Writer) {
bw.Reset(nil)
writerPool.Put(bw)
}

View File

@@ -0,0 +1,3 @@
{
"version": "v0.4.1"
}

21
vendor/github.com/multiformats/go-varint/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2019 Protocol Labs
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.

35
vendor/github.com/multiformats/go-varint/README.md generated vendored Normal file
View File

@@ -0,0 +1,35 @@
# go-varint
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai)
[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs)
[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
[![GoDoc](https://godoc.org/github.com/multiformats/go-varint?status.svg)](https://godoc.org/github.com/multiformats/go-varint)
[![Travis CI](https://img.shields.io/travis/multiformats/go-varint.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-varint)
[![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-varint.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-varint?branch=master)
> Varint helpers that enforce minimal encoding.
## Table of Contents
- [Install](#install)
- [Contribute](#contribute)
- [License](#license)
## Install
```sh
go get github.com/multiformats/go-varint
```
## Contribute
Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multiaddr/issues).
Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
## License
[MIT](LICENSE) © 2019 Protocol Labs

2
vendor/github.com/multiformats/go-varint/codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,2 @@
ignore:
- "multiaddr"

115
vendor/github.com/multiformats/go-varint/varint.go generated vendored Normal file
View File

@@ -0,0 +1,115 @@
package varint
import (
"encoding/binary"
"errors"
"io"
"math/bits"
)
var (
ErrOverflow = errors.New("varints larger than uint63 not supported")
ErrUnderflow = errors.New("varints malformed, could not reach the end")
ErrNotMinimal = errors.New("varint not minimally encoded")
)
const (
// MaxLenUvarint63 is the maximum number of bytes representing an uvarint in
// this encoding, supporting a maximum value of 2^63 (uint63), aka
// MaxValueUvarint63.
MaxLenUvarint63 = 9
// MaxValueUvarint63 is the maximum encodable uint63 value.
MaxValueUvarint63 = (1 << 63) - 1
)
// UvarintSize returns the size (in bytes) of `num` encoded as a unsigned varint.
//
// This may return a size greater than MaxUvarintLen63, which would be an
// illegal value, and would be rejected by readers.
func UvarintSize(num uint64) int {
bits := bits.Len64(num)
q, r := bits/7, bits%7
size := q
if r > 0 || size == 0 {
size++
}
return size
}
// ToUvarint converts an unsigned integer to a varint-encoded []byte
func ToUvarint(num uint64) []byte {
buf := make([]byte, UvarintSize(num))
n := binary.PutUvarint(buf, uint64(num))
return buf[:n]
}
// FromUvarint reads an unsigned varint from the beginning of buf, returns the
// varint, and the number of bytes read.
func FromUvarint(buf []byte) (uint64, int, error) {
// Modified from the go standard library. Copyright the Go Authors and
// released under the BSD License.
var x uint64
var s uint
for i, b := range buf {
if (i == 8 && b >= 0x80) || i >= MaxLenUvarint63 {
// this is the 9th and last byte we're willing to read, but it
// signals there's more (1 in MSB).
// or this is the >= 10th byte, and for some reason we're still here.
return 0, 0, ErrOverflow
}
if b < 0x80 {
if b == 0 && s > 0 {
return 0, 0, ErrNotMinimal
}
return x | uint64(b)<<s, i + 1, nil
}
x |= uint64(b&0x7f) << s
s += 7
}
return 0, 0, ErrUnderflow
}
// ReadUvarint reads a unsigned varint from the given reader.
func ReadUvarint(r io.ByteReader) (uint64, error) {
// Modified from the go standard library. Copyright the Go Authors and
// released under the BSD License.
var x uint64
var s uint
for s = 0; ; s += 7 {
b, err := r.ReadByte()
if err != nil {
if err == io.EOF && s != 0 {
// "eof" will look like a success.
// If we've read part of a value, this is not a
// success.
err = io.ErrUnexpectedEOF
}
return 0, err
}
if (s == 56 && b >= 0x80) || s >= (7*MaxLenUvarint63) {
// this is the 9th and last byte we're willing to read, but it
// signals there's more (1 in MSB).
// or this is the >= 10th byte, and for some reason we're still here.
return 0, ErrOverflow
}
if b < 0x80 {
if b == 0 && s > 0 {
return 0, ErrNotMinimal
}
return x | uint64(b)<<s, nil
}
x |= uint64(b&0x7f) << s
}
}
// PutUvarint is an alias for binary.PutUvarint.
//
// This is provided for convenience so users of this library can avoid built-in
// varint functions and easily audit code for uses of those functions.
//
// Make sure that x is smaller or equal to MaxValueUvarint63, otherwise this
// function will produce values that may be rejected by readers.
func PutUvarint(buf []byte, x uint64) int {
return binary.PutUvarint(buf, x)
}

View File

@@ -0,0 +1,3 @@
{
"version": "v0.0.7"
}