From deaa58e91fbfede04f9e07ecfdcc67a5e0876fc6 Mon Sep 17 00:00:00 2001 From: MengYX Date: Tue, 14 Dec 2021 04:01:04 +0800 Subject: [PATCH] feat(QMCv2): replace with old decoder --- algo/common/dispatch.go | 6 +- algo/qmc/old_consts.go | 70 ------------- algo/qmc/old_mask.go | 212 ---------------------------------------- algo/qmc/old_qmc.go | 129 ------------------------ algo/qmc/qmc.go | 78 +++++++++++++++ cmd/um/main.go | 31 ++++-- go.mod | 10 +- go.sum | 14 ++- 8 files changed, 119 insertions(+), 431 deletions(-) delete mode 100644 algo/qmc/old_consts.go delete mode 100644 algo/qmc/old_mask.go delete mode 100644 algo/qmc/old_qmc.go diff --git a/algo/common/dispatch.go b/algo/common/dispatch.go index faefa2a..71ce298 100644 --- a/algo/common/dispatch.go +++ b/algo/common/dispatch.go @@ -12,15 +12,15 @@ type decoderItem struct { decoder NewDecoderFunc } -var decoderRegistry = make(map[string][]decoderItem) +var DecoderRegistry = make(map[string][]decoderItem) func RegisterDecoder(ext string, noop bool, dispatchFunc NewDecoderFunc) { - decoderRegistry[ext] = append(decoderRegistry[ext], + DecoderRegistry[ext] = append(DecoderRegistry[ext], decoderItem{noop: noop, decoder: dispatchFunc}) } func GetDecoder(filename string, skipNoop bool) (rs []NewDecoderFunc) { ext := strings.ToLower(strings.TrimLeft(filepath.Ext(filename), ".")) - for _, dec := range decoderRegistry[ext] { + for _, dec := range DecoderRegistry[ext] { if skipNoop && dec.noop { continue } diff --git a/algo/qmc/old_consts.go b/algo/qmc/old_consts.go deleted file mode 100644 index 8ad25bf..0000000 --- a/algo/qmc/old_consts.go +++ /dev/null @@ -1,70 +0,0 @@ -package qmc - -var oggPublicHeader1 = []byte{ - 0x4f, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x1e, 0x01, 0x76, 0x6f, 0x72, - 0x62, 0x69, 0x73, 0x00, 0x00, 0x00, 0x00, 0x02, 0x44, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xee, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x4f, 0x67, 0x67, 0x53, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff} - -var oggPublicHeader2 = []byte{ - 0x03, 0x76, 0x6f, 0x72, 0x62, 0x69, 0x73, 0x2c, 0x00, 0x00, 0x00, 0x58, 0x69, 0x70, 0x68, 0x2e, - 0x4f, 0x72, 0x67, 0x20, 0x6c, 0x69, 0x62, 0x56, 0x6f, 0x72, 0x62, 0x69, 0x73, 0x20, 0x49, 0x20, - 0x32, 0x30, 0x31, 0x35, 0x30, 0x31, 0x30, 0x35, 0x20, 0x28, 0xe2, 0x9b, 0x84, 0xe2, 0x9b, 0x84, - 0xe2, 0x9b, 0x84, 0xe2, 0x9b, 0x84, 0x29, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3d} - -var oggPublicConfidence1 = []uint{ - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, - 0, 0, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 6, 3, 3, 3, 3, 6, 6, 6, 6, - 3, 3, 3, 3, 6, 6, 6, 6, 6, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, - 0, 0, 0, 0} - -var oggPublicConfidence2 = []uint{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 0, 1, 3, 3, 0, 1, 3, 3, 3, - 3, 3, 3, 3, 3} - -var ( - defaultKey256Mask44 = []byte{ - 0xde, 0x51, 0xfa, 0xc3, 0x4a, 0xd6, 0xca, 0x90, - 0x7e, 0x67, 0x5e, 0xf7, 0xd5, 0x52, 0x84, 0xd8, - 0x47, 0x95, 0xbb, 0xa1, 0xaa, 0xc6, 0x66, 0x23, - 0x92, 0x62, 0xf3, 0x74, 0xa1, 0x9f, 0xf4, 0xa0, - 0x1d, 0x3f, 0x5b, 0xf0, 0x13, 0x0e, 0x09, 0x3d, - 0xf9, 0xbc, 0x00, 0x11} -) -var key256MappingAll [][]int //[idx256][idx128]idx44 -var key256Mapping128to44 map[int]int - -func init() { - { // init all mapping - key256MappingAll = make([][]int, 256) - for i := 0; i < 128; i++ { - realIdx := (i*i + 27) % 256 - if key256MappingAll[realIdx] == nil { - key256MappingAll[realIdx] = []int{i} - } else { - key256MappingAll[realIdx] = append(key256MappingAll[realIdx], i) - } - } - } - { // init - key256Mapping128to44 = make(map[int]int, 128) - idx44 := 0 - for _, all128 := range key256MappingAll { - if all128 != nil { - for _, _i128 := range all128 { - key256Mapping128to44[_i128] = idx44 - } - idx44++ - } - } - } - -} diff --git a/algo/qmc/old_mask.go b/algo/qmc/old_mask.go deleted file mode 100644 index b31f33d..0000000 --- a/algo/qmc/old_mask.go +++ /dev/null @@ -1,212 +0,0 @@ -package qmc - -import ( - "bytes" - "errors" - "github.com/unlock-music/cli/algo/common" - "github.com/unlock-music/cli/internal/logging" - "go.uber.org/zap" -) - -var ( - ErrFailToMatchMask = errors.New("can not match at least one key") - ErrTestDataLength = errors.New("invalid length of test file") - ErrMaskLength128 = errors.New("incorrect mask length 128") - ErrMaskLength44 = errors.New("incorrect mask length 44") - ErrMaskDecode = errors.New("decode mask-128 to mask-58 failed") - ErrDetectFlacMask = errors.New("can not detect mflac mask") - ErrDetectMggMask = errors.New("can not detect mgg mask") -) - -type Key256Mask struct { - matrix []byte // Mask 128 -} - -func NewKey256FromMask128(mask128 []byte) (*Key256Mask, error) { - if len(mask128) != 128 { - return nil, ErrMaskLength128 - } - q := &Key256Mask{matrix: mask128} - return q, nil -} - -func NewKey256FromMask44(mask44 []byte) (*Key256Mask, error) { - mask128, err := convertKey256Mask44to128(mask44) - if err != nil { - return nil, err - } - q := &Key256Mask{matrix: mask128} - return q, nil -} - -func (q *Key256Mask) GetMatrix44() ([]byte, error) { - if len(q.matrix) != 128 { - return nil, ErrMaskLength128 - } - matrix44 := make([]byte, 44) - idx44 := 0 - for _, it256 := range key256MappingAll { - if it256 != nil { - it256Len := len(it256) - for i := 1; i < it256Len; i++ { - if q.matrix[it256[0]] != q.matrix[it256[i]] { - return nil, ErrMaskDecode - } - } - matrix44[idx44] = q.matrix[it256[0]] - idx44++ - } - } - return matrix44, nil -} - -func (q *Key256Mask) Decrypt(data []byte) []byte { - dst := make([]byte, len(data)) - index := -1 - maskIdx := -1 - for cur := 0; cur < len(data); cur++ { - index++ - maskIdx++ - if index == 0x8000 || (index > 0x8000 && (index+1)%0x8000 == 0) { - index++ - maskIdx++ - } - if maskIdx >= 128 { - maskIdx -= 128 - } - dst[cur] = data[cur] ^ q.matrix[maskIdx] - } - return dst -} - -func convertKey256Mask44to128(mask44 []byte) ([]byte, error) { - if len(mask44) != 44 { - return nil, ErrMaskLength44 - } - mask128 := make([]byte, 128) - idx44 := 0 - for _, it256 := range key256MappingAll { - if it256 != nil { - for _, idx128 := range it256 { - mask128[idx128] = mask44[idx44] - } - idx44++ - } - } - return mask128, nil -} - -func getDefaultMask() *Key256Mask { - y, _ := NewKey256FromMask44(defaultKey256Mask44) - return y -} - -func detectMflac256Mask(input []byte) (*Key256Mask, error) { - var q *Key256Mask - var rtErr = ErrDetectFlacMask - - lenData := len(input) - lenTest := 0x8000 - if lenData < 0x8000 { - lenTest = lenData - } - - for blockIdx := 0; blockIdx < lenTest; blockIdx += 128 { - var err error - q, err = NewKey256FromMask128(input[blockIdx : blockIdx+128]) - if err != nil { - continue - } - if common.SnifferFLAC(q.Decrypt(input[:4])) { - rtErr = nil - break - } - } - return q, rtErr -} - -func detectMgg256Mask(input []byte) (*Key256Mask, error) { - if len(input) < 0x100 { - return nil, ErrTestDataLength - } - - matrixConf := make([]map[uint8]uint, 44) //meaning: [idx58][value]confidence - for i := uint(0); i < 44; i++ { - matrixConf[i] = make(map[uint8]uint) - } - - page2size := input[0x54] ^ input[0xC] ^ oggPublicHeader1[0xC] - spHeader, spConf := generateOggFullHeader(int(page2size)) - lenTest := len(spHeader) - - for idx128 := 0; idx128 < lenTest; idx128++ { - confidence := spConf[idx128] - if confidence > 0 { - mask := input[idx128] ^ spHeader[idx128] - - idx44 := key256Mapping128to44[idx128&0x7f] // equals: [idx128 % 128] - if _, ok2 := matrixConf[idx44][mask]; ok2 { - matrixConf[idx44][mask] += confidence - } else { - matrixConf[idx44][mask] = confidence - } - } - } - - matrix := make([]uint8, 44) - var err error - for i := uint(0); i < 44; i++ { - matrix[i], err = decideMgg256MaskItemConf(matrixConf[i]) - if err != nil { - return nil, err - } - } - q, err := NewKey256FromMask44(matrix) - if err != nil { - return nil, err - } - if common.SnifferOGG(q.Decrypt(input[:4])) { - return q, nil - } - return nil, ErrDetectMggMask -} - -func generateOggFullHeader(pageSize int) ([]byte, []uint) { - spec := make([]byte, pageSize+1) - - spec[0], spec[1], spec[pageSize] = uint8(pageSize), 0xFF, 0xFF - for i := 2; i < pageSize; i++ { - spec[i] = 0xFF - } - specConf := make([]uint, pageSize+1) - specConf[0], specConf[1], specConf[pageSize] = 6, 0, 0 - for i := 2; i < pageSize; i++ { - specConf[i] = 4 - } - allConf := append(oggPublicConfidence1, specConf...) - allConf = append(allConf, oggPublicConfidence2...) - - allHeader := bytes.Join( - [][]byte{oggPublicHeader1, spec, oggPublicHeader2}, - []byte{}, - ) - return allHeader, allConf -} - -func decideMgg256MaskItemConf(confidence map[uint8]uint) (uint8, error) { - lenConf := len(confidence) - if lenConf == 0 { - return 0xff, ErrFailToMatchMask - } else if lenConf > 1 { - logging.Log().Warn("there are 2 potential value for the mask", zap.Any("confidence", confidence)) - } - result := uint8(0) - conf := uint(0) - for idx, item := range confidence { - if item > conf { - result = idx - conf = item - } - } - return result, nil -} diff --git a/algo/qmc/old_qmc.go b/algo/qmc/old_qmc.go deleted file mode 100644 index 54d9df0..0000000 --- a/algo/qmc/old_qmc.go +++ /dev/null @@ -1,129 +0,0 @@ -package qmc - -import ( - "encoding/base64" - "encoding/binary" - "errors" - - "github.com/unlock-music/cli/algo/common" -) - -var ( - ErrQmcFileLength = errors.New("invalid qmc file length") - ErrQmcKeyDecodeFailed = errors.New("base64 decode qmc key failed") - ErrQmcKeyLength = errors.New("unexpected decoded qmc key length") -) - -type OldDecoder struct { - file []byte - maskDetector func(encodedData []byte) (*Key256Mask, error) - mask *Key256Mask - audioExt string - key []byte - audio []byte -} - -func NewMflac256Decoder(data []byte) common.Decoder { - return &OldDecoder{file: data, maskDetector: detectMflac256Mask, audioExt: "flac"} -} - -func NewMgg256Decoder(data []byte) common.Decoder { - return &OldDecoder{file: data, maskDetector: detectMgg256Mask, audioExt: "ogg"} -} - -func (d *OldDecoder) Validate() error { - if nil != d.mask { - return nil - } - if nil != d.maskDetector { - if err := d.validateKey(); err != nil { - return err - } - var err error - d.mask, err = d.maskDetector(d.file) - return err - } - return errors.New("no mask or mask detector found") -} - -func (d *OldDecoder) validateKey() error { - lenData := len(d.file) - if lenData < 4 { - return ErrQmcFileLength - } - - keyLen := binary.LittleEndian.Uint32(d.file[lenData-4:]) - if lenData < int(keyLen+4) { - return ErrQmcFileLength - } - var err error - d.key, err = base64.StdEncoding.DecodeString( - string(d.file[lenData-4-int(keyLen) : lenData-4])) - if err != nil { - return ErrQmcKeyDecodeFailed - } - - if len(d.key) != 272 { - return ErrQmcKeyLength - } - d.file = d.file[:lenData-4-int(keyLen)] - return nil - -} - -func (d *OldDecoder) Decode() error { - d.audio = d.mask.Decrypt(d.file) - return nil -} - -func (d OldDecoder) GetCoverImage() []byte { - return nil -} - -func (d OldDecoder) GetAudioData() []byte { - return d.audio -} - -func (d OldDecoder) GetAudioExt() string { - if d.audioExt != "" { - return "." + d.audioExt - } - return "" -} - -func (d OldDecoder) GetMeta() common.Meta { - return nil -} - -func DecoderFuncWithExt(ext string) common.NewDecoderFunc { - return func(file []byte) common.Decoder { - return &OldDecoder{file: file, audioExt: ext, mask: getDefaultMask()} - } -} - -//goland:noinspection SpellCheckingInspection -func init() { - common.RegisterDecoder("qmc0", false, DecoderFuncWithExt("mp3")) //QQ Music Mp3 - common.RegisterDecoder("qmc3", false, DecoderFuncWithExt("mp3")) //QQ Music Mp3 - - common.RegisterDecoder("qmc2", false, DecoderFuncWithExt("m4a")) //QQ Music M4A - common.RegisterDecoder("qmc4", false, DecoderFuncWithExt("m4a")) //QQ Music M4A - common.RegisterDecoder("qmc6", false, DecoderFuncWithExt("m4a")) //QQ Music M4A - common.RegisterDecoder("qmc8", false, DecoderFuncWithExt("m4a")) //QQ Music M4A - - common.RegisterDecoder("qmcflac", false, DecoderFuncWithExt("flac")) //QQ Music Flac - common.RegisterDecoder("qmcogg", false, DecoderFuncWithExt("ogg")) //QQ Music Ogg - common.RegisterDecoder("tkm", false, DecoderFuncWithExt("m4a")) //QQ Music Accompaniment M4a - - common.RegisterDecoder("bkcmp3", false, DecoderFuncWithExt("mp3")) //Moo Music Mp3 - common.RegisterDecoder("bkcflac", false, DecoderFuncWithExt("flac")) //Moo Music Flac - - common.RegisterDecoder("666c6163", false, DecoderFuncWithExt("flac")) //QQ Music Weiyun Flac - common.RegisterDecoder("6d7033", false, DecoderFuncWithExt("mp3")) //QQ Music Weiyun Mp3 - common.RegisterDecoder("6f6767", false, DecoderFuncWithExt("ogg")) //QQ Music Weiyun Ogg - common.RegisterDecoder("6d3461", false, DecoderFuncWithExt("m4a")) //QQ Music Weiyun M4a - common.RegisterDecoder("776176", false, DecoderFuncWithExt("wav")) //QQ Music Weiyun Wav - - common.RegisterDecoder("mgg", false, NewMgg256Decoder) //QQ Music New Ogg - common.RegisterDecoder("mflac", false, NewMflac256Decoder) //QQ Music New Flac -} diff --git a/algo/qmc/qmc.go b/algo/qmc/qmc.go index 61a591e..9e02bf8 100644 --- a/algo/qmc/qmc.go +++ b/algo/qmc/qmc.go @@ -1,6 +1,7 @@ package qmc import ( + "bytes" "encoding/binary" "errors" "io" @@ -183,3 +184,80 @@ func (d *Decoder) readRawMetaQTag() error { return nil } + +//goland:noinspection SpellCheckingInspection +func init() { + supportedExts := []string{ + "qmc0", "qmc3", //QQ Music MP3 + "qmc2", "qmc4", "qmc6", "qmc8", //QQ Music M4A + "qmcflac", //QQ Music FLAC + "qmcogg", //QQ Music OGG + + "tkm", //QQ Music Accompaniment M4A + "bkcmp3", //Moo Music Mp3 + "bkcflac", //Moo Music Flac + + "666c6163", //QQ Music Weiyun Flac + "6d7033", //QQ Music Weiyun Mp3 + "6f6767", //QQ Music Weiyun Ogg + "6d3461", //QQ Music Weiyun M4a + "776176", //QQ Music Weiyun Wav + + "mgg", "mgg1", //QQ Music New Ogg + "mflac", "mflac0", //QQ Music New Flac + } + for _, ext := range supportedExts { + common.RegisterDecoder(ext, false, newCompactDecoder) + } +} + +type compactDecoder struct { + decoder *Decoder + createErr error + buf *bytes.Buffer +} + +func newCompactDecoder(p []byte) common.Decoder { + r := bytes.NewReader(p) + d, err := NewDecoder(r) + c := compactDecoder{ + decoder: d, + createErr: err, + } + return &c +} + +func (c *compactDecoder) Validate() error { + if c.createErr != nil { + return c.createErr + } + return c.decoder.Validate() +} + +func (c *compactDecoder) Decode() error { + if c.createErr != nil { + return c.createErr + } + c.buf = bytes.NewBuffer(nil) + _, err := io.Copy(c.buf, c.decoder) + return err +} + +func (c *compactDecoder) GetCoverImage() []byte { + return nil +} + +func (c *compactDecoder) GetAudioData() []byte { + return c.buf.Bytes() +} + +func (c *compactDecoder) GetAudioExt() string { + if c.createErr != nil { + return "" + } + return c.decoder.GetFileExt() +} + +func (c *compactDecoder) GetMeta() common.Meta { + return nil +} diff --git a/cmd/um/main.go b/cmd/um/main.go index fbcbec6..74a4fc2 100644 --- a/cmd/um/main.go +++ b/cmd/um/main.go @@ -3,6 +3,15 @@ package main import ( "errors" "fmt" + "os" + "path/filepath" + "runtime" + "sort" + "strings" + + "github.com/urfave/cli/v2" + "go.uber.org/zap" + "github.com/unlock-music/cli/algo/common" _ "github.com/unlock-music/cli/algo/kgm" _ "github.com/unlock-music/cli/algo/kwm" @@ -11,12 +20,6 @@ import ( _ "github.com/unlock-music/cli/algo/tm" _ "github.com/unlock-music/cli/algo/xm" "github.com/unlock-music/cli/internal/logging" - "github.com/urfave/cli/v2" - "go.uber.org/zap" - "os" - "path/filepath" - "runtime" - "strings" ) var AppVersion = "v0.0.6" @@ -31,6 +34,7 @@ func main() { &cli.StringFlag{Name: "input", Aliases: []string{"i"}, Usage: "path to input file or dir", Required: false}, &cli.StringFlag{Name: "output", Aliases: []string{"o"}, Usage: "path to output dir", Required: false}, &cli.BoolFlag{Name: "skip-noop", Aliases: []string{"n"}, Usage: "skip noop decoder", Required: false, Value: true}, + &cli.BoolFlag{Name: "supported-ext", Usage: "Show supported file extensions and exit", Required: false, Value: false}, }, Action: appMain, @@ -43,8 +47,21 @@ func main() { logging.Log().Fatal("run app failed", zap.Error(err)) } } - +func printSupportedExtensions() { + exts := []string{} + for ext := range common.DecoderRegistry { + exts = append(exts, ext) + } + sort.Strings(exts) + for _, ext := range exts { + fmt.Printf("%s: %d\n", ext, len(common.DecoderRegistry[ext])) + } +} func appMain(c *cli.Context) (err error) { + if c.Bool("supported-ext") { + printSupportedExtensions() + return nil + } input := c.String("input") if input == "" { switch c.Args().Len() { diff --git a/go.mod b/go.mod index bc67651..5326dd1 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,12 @@ require ( github.com/ulikunitz/xz v0.5.10 github.com/urfave/cli/v2 v2.3.0 go.uber.org/zap v1.19.1 + golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 ) require ( - github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect - github.com/russross/blackfriday/v2 v2.0.1 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.7.0 // indirect ) diff --git a/go.sum b/go.sum index 46b5493..9f00169 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,9 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -13,9 +14,9 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -26,15 +27,18 @@ github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0o github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=