upgrade deps, clean up (#83)
This commit is contained in:
1
vendor/github.com/creachadair/otp/.gitignore
generated
vendored
Normal file
1
vendor/github.com/creachadair/otp/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
.go-update
|
3
vendor/github.com/creachadair/otp/go.mod
generated
vendored
3
vendor/github.com/creachadair/otp/go.mod
generated
vendored
@ -1,3 +0,0 @@
|
||||
module github.com/creachadair/otp
|
||||
|
||||
go 1.18
|
3
vendor/github.com/creachadair/otp/otp.go
generated
vendored
3
vendor/github.com/creachadair/otp/otp.go
generated
vendored
@ -146,6 +146,9 @@ func (c Config) format(v []byte, nd int) string {
|
||||
|
||||
// Truncate truncates the specified digest using the algorithm from RFC 4226.
|
||||
// Only the low-order 31 bits of the value are populated; the rest are zero.
|
||||
//
|
||||
// Note that RFC 6238 stipulates the same truncation algorithm regardless of
|
||||
// the length of the chosen digest.
|
||||
func Truncate(digest []byte) uint64 {
|
||||
offset := digest[len(digest)-1] & 0x0f
|
||||
code := (uint64(digest[offset]&0x7f) << 24) |
|
||||
|
164
vendor/github.com/creachadair/otp/otpauth/migration.go
generated
vendored
Normal file
164
vendor/github.com/creachadair/otp/otpauth/migration.go
generated
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
package otpauth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/creachadair/wirepb"
|
||||
)
|
||||
|
||||
// ParseMigrationURL parses an otpauth-migration URL in the format generated by
|
||||
// the Google Authenticator for "exported" configurations. Typically these URLs
|
||||
// are embedded as QR codes, encoding a proprietary URL in this format:
|
||||
//
|
||||
// otpauth-migration://offline?data=<content>
|
||||
//
|
||||
// The content is a protocol buffer message encoded as base64 in standard
|
||||
// encoding. Note that a single migration URL may encode multiple OTP
|
||||
// settings; on success this function returns all the otpauth URLs encoded by
|
||||
// the content. It will always return at least one URL, or report an error.
|
||||
func ParseMigrationURL(s string) ([]*URL, error) {
|
||||
rest, ok := strings.CutPrefix(s, "otpauth-migration://")
|
||||
if !ok {
|
||||
return nil, errors.New("missing otpauth-migration schema prefix")
|
||||
}
|
||||
content, ok := strings.CutPrefix(rest, "offline?data=")
|
||||
if !ok {
|
||||
return nil, errors.New("unrecognized path format")
|
||||
}
|
||||
dec, err := url.QueryUnescape(content)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid data: %w", err)
|
||||
}
|
||||
bits, err := base64.StdEncoding.DecodeString(dec)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid base64: %w", err)
|
||||
}
|
||||
return parseMigrations(bits)
|
||||
}
|
||||
|
||||
/*
|
||||
The content of a migration URL is a wire-format protocol buffer message.
|
||||
|
||||
I don't want to take a dependency on protobuf, since that pulls in a lot of
|
||||
other expensive Google nonsense, but fortunately the message structure is
|
||||
fairly simple:
|
||||
|
||||
message Content {
|
||||
repeated Params params = 1;
|
||||
|
||||
// ... other fields not of interest.
|
||||
// If you're exporting more data than can fit in one QR code, the app may
|
||||
// split up the export into multiple codes. There are some fields here to
|
||||
// keep track of that, but they aren't relevant here.
|
||||
}
|
||||
|
||||
message Params {
|
||||
bytes secret = 1;
|
||||
string account = 2;
|
||||
string issuer = 3;
|
||||
int32 algorithm = 4; // 0: unspec, 1: SHA1, 2: SHA256, 3: SHA512, 4: MD5
|
||||
int32 digits = 5; // 0: unspec, 1: 6 digits, 2: 8 digits (typical Google)
|
||||
int32 type = 6; // 0: unspec, 1: HOTP, 2: TOTP
|
||||
uint64 counter = 7;
|
||||
}
|
||||
|
||||
So here we just unpack the wire format directly.
|
||||
*/
|
||||
|
||||
// parseMigrations parses data as a wire-format protobuf message in the Content
|
||||
// format described above, and returns a single URL for each instance of the
|
||||
// Params found therein. Other fields of the message are ignored.
|
||||
func parseMigrations(data []byte) ([]*URL, error) {
|
||||
const paramsField = 1
|
||||
|
||||
var out []*URL
|
||||
s := wirepb.NewScanner(bytes.NewReader(data))
|
||||
for s.Next() == nil {
|
||||
if s.ID() == paramsField {
|
||||
u, err := parseParams(s.Data())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, u)
|
||||
}
|
||||
}
|
||||
if s.Err() != io.EOF {
|
||||
return nil, s.Err()
|
||||
} else if len(out) == 0 {
|
||||
return nil, errors.New("no URLs found")
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func parseParams(data []byte) (*URL, error) {
|
||||
const (
|
||||
secretField = 1 + iota
|
||||
accountField
|
||||
issuerField
|
||||
algorithmField
|
||||
digitsField
|
||||
typeField
|
||||
counterField
|
||||
)
|
||||
|
||||
var out = URL{Algorithm: defaultAlgorithm, Digits: defaultDigits, Period: defaultPeriod}
|
||||
s := wirepb.NewScanner(bytes.NewReader(data))
|
||||
for s.Next() == nil {
|
||||
switch s.ID() {
|
||||
case secretField:
|
||||
out.SetSecret(s.Data())
|
||||
case accountField:
|
||||
out.Account = string(s.Data())
|
||||
case issuerField:
|
||||
out.Issuer = string(s.Data())
|
||||
case algorithmField:
|
||||
switch v, _ := binary.Uvarint(s.Data()); v {
|
||||
case 1:
|
||||
out.Algorithm = "SHA1"
|
||||
case 2:
|
||||
out.Algorithm = "SHA256"
|
||||
case 3:
|
||||
out.Algorithm = "SHA512"
|
||||
case 4:
|
||||
out.Algorithm = "MD5"
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown algorithm code %d", v)
|
||||
}
|
||||
case digitsField:
|
||||
switch v, _ := binary.Uvarint(s.Data()); v {
|
||||
case 1:
|
||||
out.Digits = 6
|
||||
case 2:
|
||||
out.Digits = 8
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown digits code %d", v)
|
||||
}
|
||||
case typeField:
|
||||
switch v, _ := binary.Uvarint(s.Data()); v {
|
||||
case 1:
|
||||
out.Type = "hotp"
|
||||
case 2:
|
||||
out.Type = "totp"
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown type code %d", v)
|
||||
}
|
||||
case counterField:
|
||||
v, n := binary.Uvarint(s.Data())
|
||||
if n <= 0 {
|
||||
return nil, errors.New("invalid counter value")
|
||||
}
|
||||
out.Counter = v
|
||||
}
|
||||
}
|
||||
if s.Err() != io.EOF {
|
||||
return nil, s.Err()
|
||||
}
|
||||
return &out, nil
|
||||
}
|
12
vendor/github.com/creachadair/otp/otpauth/otpauth.go
generated
vendored
12
vendor/github.com/creachadair/otp/otpauth/otpauth.go
generated
vendored
@ -60,7 +60,7 @@ func (u *URL) String() string {
|
||||
// Encode parameters if there are any non-default values.
|
||||
var params []string
|
||||
if a := strings.ToUpper(u.Algorithm); a != "" && a != "SHA1" {
|
||||
params = append(params, "algorithm="+url.PathEscape(a))
|
||||
params = append(params, "algorithm="+queryEscape(a))
|
||||
}
|
||||
if c := u.Counter; c > 0 || typ == "hotp" {
|
||||
params = append(params, "counter="+strconv.FormatUint(c, 10))
|
||||
@ -69,14 +69,14 @@ func (u *URL) String() string {
|
||||
params = append(params, "digits="+strconv.Itoa(d))
|
||||
}
|
||||
if o := u.Issuer; o != "" {
|
||||
params = append(params, "issuer="+url.PathEscape(o))
|
||||
params = append(params, "issuer="+queryEscape(o))
|
||||
}
|
||||
if p := u.Period; p > 0 && p != defaultPeriod {
|
||||
params = append(params, "period="+strconv.Itoa(p))
|
||||
}
|
||||
if s := u.RawSecret; s != "" {
|
||||
enc := strings.ToUpper(strings.Join(strings.Fields(strings.TrimRight(s, "=")), ""))
|
||||
params = append(params, "secret="+url.PathEscape(enc))
|
||||
params = append(params, "secret="+queryEscape(enc))
|
||||
}
|
||||
if len(params) != 0 {
|
||||
sb.WriteByte('?')
|
||||
@ -182,7 +182,7 @@ func ParseURL(s string) (*URL, error) {
|
||||
if len(ps) == 1 {
|
||||
ps = append(ps, "") // check value below
|
||||
}
|
||||
value, err := url.PathUnescape(ps[1])
|
||||
value, err := url.QueryUnescape(ps[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid value: %v", err)
|
||||
}
|
||||
@ -219,3 +219,7 @@ func ParseURL(s string) (*URL, error) {
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func queryEscape(s string) string {
|
||||
return strings.ReplaceAll(url.QueryEscape(s), "+", "%20")
|
||||
}
|
||||
|
Reference in New Issue
Block a user