diff --git a/go.mod b/go.mod index 84567cc60b628681978eb197659b6703e32ab80f..cbf56ee1b26f4bc57ba182acc3ebbd3a5a13d6cc 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/mattn/go-colorable v0.1.6 // indirect github.com/mattn/go-sqlite3 v1.14.16 github.com/patrickmn/go-cache v0.0.0-20180815053127-5633e0862627 - github.com/pquerna/otp v1.3.0 + github.com/pquerna/otp v1.4.0 github.com/prometheus/client_golang v1.12.2 github.com/theckman/go-flock v0.8.1 go.opentelemetry.io/otel v1.10.0 diff --git a/go.sum b/go.sum index e18b419fc6e04ec73fa5accf5be84a55174d2caf..08775c34867815a953bda680625da3aa9893e45f 100644 --- a/go.sum +++ b/go.sum @@ -721,6 +721,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs= github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= +github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= diff --git a/vendor/github.com/pquerna/otp/README.md b/vendor/github.com/pquerna/otp/README.md index 4cb9b71dc3051b27f00c7e13c9d205a6465077b2..1447e3a49448fa8588b8eab3154d9d009c66358f 100644 --- a/vendor/github.com/pquerna/otp/README.md +++ b/vendor/github.com/pquerna/otp/README.md @@ -4,7 +4,7 @@ # Why One Time Passwords? -One Time Passwords (OTPs) are an mechanism to improve security over passwords alone. When a Time-based OTP (TOTP) is stored on a user's phone, and combined with something the user knows (Password), you have an easy on-ramp to [Multi-factor authentication](http://en.wikipedia.org/wiki/Multi-factor_authentication) without adding a dependency on a SMS provider. This Password and TOTP combination is used by many popular websites including Google, Github, Facebook, Salesforce and many others. +One Time Passwords (OTPs) are an mechanism to improve security over passwords alone. When a Time-based OTP (TOTP) is stored on a user's phone, and combined with something the user knows (Password), you have an easy on-ramp to [Multi-factor authentication](http://en.wikipedia.org/wiki/Multi-factor_authentication) without adding a dependency on a SMS provider. This Password and TOTP combination is used by many popular websites including Google, GitHub, Facebook, Salesforce and many others. The `otp` library enables you to easily add TOTPs to your own application, increasing your user's security against mass-password breaches and malware. @@ -21,7 +21,7 @@ Because TOTP is standardized and widely deployed, there are many [mobile clients ### User Enrollment -For an example of a working enrollment work flow, [Github has documented theirs](https://help.github.com/articles/configuring-two-factor-authentication-via-a-totp-mobile-app/ +For an example of a working enrollment work flow, [GitHub has documented theirs](https://help.github.com/articles/configuring-two-factor-authentication-via-a-totp-mobile-app/ ), but the basics are: 1. Generate new TOTP Key for a User. `key,_ := totp.Generate(...)`. diff --git a/vendor/github.com/pquerna/otp/doc.go b/vendor/github.com/pquerna/otp/doc.go index b8b4c8cc193f9d1ea4bb4ac37cea3990b69ce041..bb195457e5e570c1265be5d93128a36374a39543 100644 --- a/vendor/github.com/pquerna/otp/doc.go +++ b/vendor/github.com/pquerna/otp/doc.go @@ -19,7 +19,7 @@ // one time passcodes in a Google Authenticator compatible manner. // // When adding a TOTP for a user, you must store the "secret" value -// persistently. It is recommend to store the secret in an encrypted field in your +// persistently. It is recommended to store the secret in an encrypted field in your // datastore. Due to how TOTP works, it is not possible to store a hash // for the secret value like you would a password. // @@ -57,6 +57,7 @@ // // Validating a TOTP passcode is very easy, just prompt the user for a passcode // and retrieve the associated user's previously stored secret. +// // import "github.com/pquerna/otp/totp" // // passcode := promptForPasscode() diff --git a/vendor/github.com/pquerna/otp/go.sum b/vendor/github.com/pquerna/otp/go.sum index 6848b56f62571400990d0b8a68a3b4ef12476865..6db19d59b70bea129a1279a1fb7d7c000430542c 100644 --- a/vendor/github.com/pquerna/otp/go.sum +++ b/vendor/github.com/pquerna/otp/go.sum @@ -1,5 +1,3 @@ -github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= diff --git a/vendor/github.com/pquerna/otp/hotp/hotp.go b/vendor/github.com/pquerna/otp/hotp/hotp.go index 7b94734045b1878ac882fcdac89ae3a382b2fe0e..13a193e94c7cbca6a7a82ef1fb64004045a4197d 100644 --- a/vendor/github.com/pquerna/otp/hotp/hotp.go +++ b/vendor/github.com/pquerna/otp/hotp/hotp.go @@ -19,6 +19,7 @@ package hotp import ( "github.com/pquerna/otp" + "github.com/pquerna/otp/internal" "io" "crypto/hmac" @@ -71,6 +72,10 @@ func GenerateCode(secret string, counter uint64) (string, error) { // GenerateCodeCustom uses a counter and secret value and options struct to // create a passcode. func GenerateCodeCustom(secret string, counter uint64, opts ValidateOpts) (passcode string, err error) { + //Set default value + if opts.Digits == 0 { + opts.Digits = otp.DigitsSix + } // As noted in issue #10 and #17 this adds support for TOTP secrets that are // missing their padding. secret = strings.TrimSpace(secret) @@ -182,7 +187,7 @@ func Generate(opts GenerateOpts) (*otp.Key, error) { opts.Rand = rand.Reader } - // otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example + // otpauth://hotp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example v := url.Values{} if len(opts.Secret) != 0 { @@ -204,7 +209,7 @@ func Generate(opts GenerateOpts) (*otp.Key, error) { Scheme: "otpauth", Host: "hotp", Path: "/" + opts.Issuer + ":" + opts.AccountName, - RawQuery: v.Encode(), + RawQuery: internal.EncodeQuery(v), } return otp.NewKeyFromURL(u.String()) diff --git a/vendor/github.com/pquerna/otp/internal/encode.go b/vendor/github.com/pquerna/otp/internal/encode.go new file mode 100644 index 0000000000000000000000000000000000000000..2af3c8bc057147ba205ce1e1dabdb7c17670c898 --- /dev/null +++ b/vendor/github.com/pquerna/otp/internal/encode.go @@ -0,0 +1,35 @@ +package internal + +import ( + "net/url" + "sort" + "strings" +) + +// EncodeQuery is a copy-paste of url.Values.Encode, except it uses %20 instead +// of + to encode spaces. This is necessary to correctly render spaces in some +// authenticator apps, like Google Authenticator. +func EncodeQuery(v url.Values) string { + if v == nil { + return "" + } + var buf strings.Builder + keys := make([]string, 0, len(v)) + for k := range v { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + vs := v[k] + keyEscaped := url.PathEscape(k) // changed from url.QueryEscape + for _, v := range vs { + if buf.Len() > 0 { + buf.WriteByte('&') + } + buf.WriteString(keyEscaped) + buf.WriteByte('=') + buf.WriteString(url.PathEscape(v)) // changed from url.QueryEscape + } + } + return buf.String() +} diff --git a/vendor/github.com/pquerna/otp/otp.go b/vendor/github.com/pquerna/otp/otp.go index 9f20983709ffaca966ac12e55498c6b0a4e4db21..02b08f317abfba24eb816fa89193bdfe00428e14 100644 --- a/vendor/github.com/pquerna/otp/otp.go +++ b/vendor/github.com/pquerna/otp/otp.go @@ -18,9 +18,6 @@ package otp import ( - "github.com/boombuler/barcode" - "github.com/boombuler/barcode/qr" - "crypto/md5" "crypto/sha1" "crypto/sha256" @@ -30,8 +27,11 @@ import ( "hash" "image" "net/url" - "strings" "strconv" + "strings" + + "github.com/boombuler/barcode" + "github.com/boombuler/barcode/qr" ) // Error when attempting to convert the secret from base32 to raw bytes. @@ -61,7 +61,6 @@ func NewKeyFromURL(orig string) (*Key, error) { s := strings.TrimSpace(orig) u, err := url.Parse(s) - if err != nil { return nil, err } @@ -81,7 +80,6 @@ func (k *Key) String() string { // to enroll a user's TOTP/HOTP key. func (k *Key) Image(width int, height int) (image.Image, error) { b, err := qr.Encode(k.orig, qr.M, qr.Auto) - if err != nil { return nil, err } @@ -146,11 +144,45 @@ func (k *Key) Period() uint64 { if u, err := strconv.ParseUint(q.Get("period"), 10, 64); err == nil { return u } - + // If no period is defined 30 seconds is the default per (rfc6238) return 30 } +// Digits returns a tiny int representing the number of OTP digits. +func (k *Key) Digits() Digits { + q := k.url.Query() + + if u, err := strconv.ParseUint(q.Get("digits"), 10, 64); err == nil { + switch u { + case 8: + return DigitsEight + default: + return DigitsSix + } + } + + // Six is the most common value. + return DigitsSix +} + +// Algorithm returns the algorithm used or the default (SHA1). +func (k *Key) Algorithm() Algorithm { + q := k.url.Query() + + a := strings.ToLower(q.Get("algorithm")) + switch a { + case "md5": + return AlgorithmMD5 + case "sha256": + return AlgorithmSHA256 + case "sha512": + return AlgorithmSHA512 + default: + return AlgorithmSHA1 + } +} + // URL returns the OTP URL as a string func (k *Key) URL() string { return k.url.String() diff --git a/vendor/github.com/pquerna/otp/totp/totp.go b/vendor/github.com/pquerna/otp/totp/totp.go index db5ed36d828e9dfc99ffa084c658bde51739b51c..a2fb7d55712dff0046305131c82af4bf6acc79fe 100644 --- a/vendor/github.com/pquerna/otp/totp/totp.go +++ b/vendor/github.com/pquerna/otp/totp/totp.go @@ -20,6 +20,7 @@ package totp import ( "github.com/pquerna/otp" "github.com/pquerna/otp/hotp" + "github.com/pquerna/otp/internal" "io" "crypto/rand" @@ -199,7 +200,7 @@ func Generate(opts GenerateOpts) (*otp.Key, error) { Scheme: "otpauth", Host: "totp", Path: "/" + opts.Issuer + ":" + opts.AccountName, - RawQuery: v.Encode(), + RawQuery: internal.EncodeQuery(v), } return otp.NewKeyFromURL(u.String()) diff --git a/vendor/modules.txt b/vendor/modules.txt index cb73742d16443eaa4bb1852e5fec942c12820ee4..acec1634bad74167d39c6a5d33468f275f4f6d2d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -236,10 +236,11 @@ github.com/openzipkin/zipkin-go/model # github.com/patrickmn/go-cache v0.0.0-20180815053127-5633e0862627 ## explicit github.com/patrickmn/go-cache -# github.com/pquerna/otp v1.3.0 +# github.com/pquerna/otp v1.4.0 ## explicit github.com/pquerna/otp github.com/pquerna/otp/hotp +github.com/pquerna/otp/internal github.com/pquerna/otp/totp # github.com/prometheus/client_golang v1.12.2 ## explicit