diff --git a/go.mod b/go.mod
index 0db5a5f9..5bc78ef0 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,6 @@ module github.com/mickael-kerjean/filestash
go 1.16
require (
- github.com/abbot/go-http-auth v0.4.1-0.20220112235402-e1cee1c72f2f
github.com/aws/aws-sdk-go v1.40.41
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect
github.com/creack/pty v1.1.18
@@ -28,6 +27,7 @@ require (
github.com/stretchr/testify v1.7.0
github.com/tidwall/gjson v1.13.0
github.com/tidwall/sjson v1.0.4
+ github.com/tredoe/osutil v1.0.6
github.com/wayneashleyberry/terminal-dimensions v1.1.0 // indirect
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed
golang.org/x/image v0.0.0-20210622092929-e6eecd499c2c
diff --git a/go.sum b/go.sum
index 8afb48d0..6d28f817 100644
--- a/go.sum
+++ b/go.sum
@@ -3,8 +3,6 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/abbot/go-http-auth v0.4.1-0.20220112235402-e1cee1c72f2f h1:R2ZVGCZzU95oXFJxncosHS9LsX8N4/MYUdGGWOb2cFk=
-github.com/abbot/go-http-auth v0.4.1-0.20220112235402-e1cee1c72f2f/go.mod h1:l2P3JyHa+fjy5Bxol6y1u2o4DV/mv3QMBdBu2cNR53w=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
@@ -143,6 +141,10 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.0.4 h1:UcdIRXff12Lpnu3OLtZvnc03g4vH2suXDXhBwBqmzYg=
github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y=
+github.com/tredoe/fileutil v1.0.5/go.mod h1:HFzzpvg+3Q8LgmZgo1mVF5epHc/CVkWKEb3hja+/1Zo=
+github.com/tredoe/goutil v1.0.0/go.mod h1:Qhf75QLcNEChimbl4wb8nROzw9PCFCPYTEUmTnoszXY=
+github.com/tredoe/osutil v1.0.6 h1:KJvG9AFmUPLe3hsNKyPMIjNx77CkAJtMKVS4ugAT7vM=
+github.com/tredoe/osutil v1.0.6/go.mod h1:zNq93p2DLHJWkHi2/+zi3xOjZl8xxiv3tiI2A6zcB3w=
github.com/wayneashleyberry/terminal-dimensions v1.1.0 h1:EB7cIzBdsOzAgmhTUtTTQXBByuPheP/Zv1zL2BRPY6g=
github.com/wayneashleyberry/terminal-dimensions v1.1.0/go.mod h1:2lc/0eWCObmhRczn2SdGSQtgBooLUzIotkkEGXqghyg=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
@@ -157,7 +159,6 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed h1:YoWVYYAfvQ4ddHv3OKmIvX7NCAhFGTj62VP2l2kfBbA=
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -181,7 +182,6 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
diff --git a/server/plugin/plg_authenticate_admin/index.go b/server/plugin/plg_authenticate_admin/index.go
index bb0be76d..6b01a33e 100644
--- a/server/plugin/plg_authenticate_admin/index.go
+++ b/server/plugin/plg_authenticate_admin/index.go
@@ -56,7 +56,10 @@ func (this Admin) EntryPoint(idpParams map[string]string, req *http.Request, res
` + getFlash() + `
-
+
`)))
return nil
}
diff --git a/server/plugin/plg_authenticate_htpasswd/index.go b/server/plugin/plg_authenticate_htpasswd/index.go
index d013f0d0..90f13beb 100644
--- a/server/plugin/plg_authenticate_htpasswd/index.go
+++ b/server/plugin/plg_authenticate_htpasswd/index.go
@@ -1,9 +1,16 @@
-package plg_authenticate_passthrough
+package plg_authenticate_htpasswd
import (
+ "crypto/sha1"
+ "crypto/subtle"
+ "encoding/base64"
"fmt"
- auth "github.com/abbot/go-http-auth"
. "github.com/mickael-kerjean/filestash/server/common"
+ "github.com/tredoe/osutil/user/crypt"
+ "github.com/tredoe/osutil/user/crypt/apr1_crypt"
+ "github.com/tredoe/osutil/user/crypt/md5_crypt"
+ "github.com/tredoe/osutil/user/crypt/sha256_crypt"
+ "github.com/tredoe/osutil/user/crypt/sha512_crypt"
"net/http"
"strings"
)
@@ -23,11 +30,18 @@ func (this Htpasswd) Setup() Form {
Value: "htpasswd",
},
{
- Name: "users",
- Type: "long_text",
- Placeholder: "test:$apr1$nEDlyMK/$4jL0BUAuEifz2VajdjVnE.\ntest:{SHA}qUqP5cyxm6YcTAhz05Hph5gvu9M=",
- Default: "",
- Description: `The list of users who are granted access using the htpasswd file format.
+ Name: "users",
+ Type: "long_text",
+ Placeholder: `test1:$apr1$ZiAIyyhS$ovyMo9eJRgDF/luvmAigP0
+test2:{SHA}EJ9LPFDXsN9ynSmbxvjp75Bmlx8=
+test3:$6$ME6DxvSEUjW4Kx/j$vQ5Yh1utmNEr4EZnWH0ZQa6hrG5yu2siybFW10aAax4u611W9awI5V90YWqGs4NjTSHkCrhpdbJoNErW9/Pbh1:19306:0:99999:7:::
+test4:$6$wTy86P73X/DsCiQy$El3JVUjepBUO.e.1OTuDt4yL9w2CnzY4jHaIbg1P7p508n8vjzCC8ZNsWa1IlbhciBM8.0LqqXWi3OuhGfPmP.
+test5:$5$RkdUxGLHGhmrO0yj$K6bCqmB.OPR7KM4i5eiAG.mxFyhElLNdthSL.dreqN5
+test6:$1$vuUKD.37$R6eCPFBa6lKIVfnkABveB1`,
+ Default: "",
+ Description: `The list of users who are granted access using either or both the htpasswd file format or the /etc/shadow file format. To generate a password:
+'openssl passwd -6' or 'mkpasswd -m SHA-512' or the htpasswd cli tool.
+
This plugin exposes {{ .user }} and {{ .password }} for the attribute mapping section`,
},
},
@@ -59,7 +73,10 @@ func (this Htpasswd) EntryPoint(idpParams map[string]string, req *http.Request,
` + getFlash() + `
-
+
`)))
return nil
}
@@ -76,7 +93,10 @@ func (this Htpasswd) Callback(formData map[string]string, idpParams map[string]s
continue
} else if formData["user"] != pair[0] {
continue
- } else if auth.CheckSecret(formData["password"], pair[1]) == false {
+ } else if verifyPassword(
+ formData["password"],
+ strings.SplitN(pair[1], ":", 2)[0], // filter out unwanted fields from hash
+ ) == false {
continue
}
return map[string]string{
@@ -92,3 +112,46 @@ func (this Htpasswd) Callback(formData map[string]string, idpParams map[string]s
})
return nil, ErrAuthenticationFailed
}
+
+func verifyPassword(password string, hash string) bool {
+ if strings.HasPrefix(hash, "{SHA}") {
+ d := sha1.New()
+ d.Write([]byte(password))
+ return subtle.ConstantTimeCompare(
+ []byte(strings.TrimPrefix(hash, "{SHA}")),
+ []byte(base64.StdEncoding.EncodeToString(d.Sum(nil))),
+ ) == 1
+ }
+ var c crypt.Crypter
+ parts := strings.SplitN(hash, "$", 4)
+ if len(parts) != 4 {
+ return false
+ }
+ if strings.HasPrefix(hash, "$apr1$") {
+ c = apr1_crypt.New()
+ parts[2] = "$apr1$" + parts[2]
+ } else if strings.HasPrefix(hash, "$6$") {
+ c = sha512_crypt.New()
+ parts[2] = "$6$" + parts[2]
+ } else if strings.HasPrefix(hash, "$5$") {
+ c = sha256_crypt.New()
+ parts[2] = "$5$" + parts[2]
+ } else if strings.HasPrefix(hash, "$1$") {
+ c = md5_crypt.New()
+ parts[2] = "$1$" + parts[2]
+ } else {
+ // TODO: there are other algorithm available but that's another job
+ // for another day
+ return false
+ }
+ shadow, err := c.Generate(
+ []byte(password),
+ []byte(parts[2]),
+ )
+ if err != nil {
+ return false
+ } else if shadow != hash {
+ return false
+ }
+ return true
+}
diff --git a/vendor/github.com/abbot/go-http-auth/.gitignore b/vendor/github.com/abbot/go-http-auth/.gitignore
deleted file mode 100644
index 112ea395..00000000
--- a/vendor/github.com/abbot/go-http-auth/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-*~
-*.a
-*.6
-*.out
-_testmain.go
diff --git a/vendor/github.com/abbot/go-http-auth/LICENSE b/vendor/github.com/abbot/go-http-auth/LICENSE
deleted file mode 100644
index e454a525..00000000
--- a/vendor/github.com/abbot/go-http-auth/LICENSE
+++ /dev/null
@@ -1,178 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/vendor/github.com/abbot/go-http-auth/Makefile b/vendor/github.com/abbot/go-http-auth/Makefile
deleted file mode 100644
index 25f208da..00000000
--- a/vendor/github.com/abbot/go-http-auth/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include $(GOROOT)/src/Make.inc
-
-TARG=auth_digest
-GOFILES=\
- auth.go\
- digest.go\
- basic.go\
- misc.go\
- md5crypt.go\
- users.go\
-
-include $(GOROOT)/src/Make.pkg
diff --git a/vendor/github.com/abbot/go-http-auth/README.md b/vendor/github.com/abbot/go-http-auth/README.md
deleted file mode 100644
index 73ae9852..00000000
--- a/vendor/github.com/abbot/go-http-auth/README.md
+++ /dev/null
@@ -1,71 +0,0 @@
-HTTP Authentication implementation in Go
-========================================
-
-This is an implementation of HTTP Basic and HTTP Digest authentication
-in Go language. It is designed as a simple wrapper for
-http.RequestHandler functions.
-
-Features
---------
-
- * Supports HTTP Basic and HTTP Digest authentication.
- * Supports htpasswd and htdigest formatted files.
- * Automatic reloading of password files.
- * Pluggable interface for user/password storage.
- * Supports MD5, SHA1 and BCrypt for Basic authentication password storage.
- * Configurable Digest nonce cache size with expiration.
- * Wrapper for legacy http handlers (http.HandlerFunc interface)
-
-Example usage
--------------
-
-This is a complete working example for Basic auth:
-
- package main
-
- import (
- "fmt"
- "net/http"
-
- auth "github.com/abbot/go-http-auth"
- )
-
- func Secret(user, realm string) string {
- if user == "john" {
- // password is "hello"
- return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
- }
- return ""
- }
-
- func handle(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
- fmt.Fprintf(w, "
Hello, %s!
", r.Username)
- }
-
- func main() {
- authenticator := auth.NewBasicAuthenticator("example.com", Secret)
- http.HandleFunc("/", authenticator.Wrap(handle))
- http.ListenAndServe(":8080", nil)
- }
-
-See more examples in the "examples" directory.
-
-Legal
------
-
-This module is developed under Apache 2.0 license, and can be used for
-open and proprietary projects.
-
-Copyright 2012-2013 Lev Shamardin
-
-Licensed under the Apache License, Version 2.0 (the "License"); you
-may not use this file or any other part of this project 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.
diff --git a/vendor/github.com/abbot/go-http-auth/auth.go b/vendor/github.com/abbot/go-http-auth/auth.go
deleted file mode 100644
index bbe5a129..00000000
--- a/vendor/github.com/abbot/go-http-auth/auth.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// Package auth is an implementation of HTTP Basic and HTTP Digest authentication.
-package auth
-
-import (
- "context"
- "net/http"
-)
-
-// AuthenticatedRequest is passed to AuthenticatedHandlerFunc instead
-// of *http.Request.
-type AuthenticatedRequest struct {
- http.Request
- // Username is the authenticated user name. Current API implies that
- // Username is never empty, which means that authentication is
- // always done before calling the request handler.
- Username string
-}
-
-// AuthenticatedHandlerFunc is like http.HandlerFunc, but takes
-// AuthenticatedRequest instead of http.Request
-type AuthenticatedHandlerFunc func(http.ResponseWriter, *AuthenticatedRequest)
-
-// Authenticator wraps an AuthenticatedHandlerFunc with
-// authentication-checking code.
-//
-// Typical Authenticator usage is something like:
-//
-// authenticator := SomeAuthenticator(...)
-// http.HandleFunc("/", authenticator(my_handler))
-//
-// Authenticator wrapper checks the user authentication and calls the
-// wrapped function only after authentication has succeeded. Otherwise,
-// it returns a handler which initiates the authentication procedure.
-type Authenticator func(AuthenticatedHandlerFunc) http.HandlerFunc
-
-// Info contains authentication information for the request.
-type Info struct {
- // Authenticated is set to true when request was authenticated
- // successfully, i.e. username and password passed in request did
- // pass the check.
- Authenticated bool
-
- // Username contains a user name passed in the request when
- // Authenticated is true. It's value is undefined if Authenticated
- // is false.
- Username string
-
- // ResponseHeaders contains extra headers that must be set by server
- // when sending back HTTP response.
- ResponseHeaders http.Header
-}
-
-// UpdateHeaders updates headers with this Info's ResponseHeaders. It is
-// safe to call this function on nil Info.
-func (i *Info) UpdateHeaders(headers http.Header) {
- if i == nil {
- return
- }
- for k, values := range i.ResponseHeaders {
- for _, v := range values {
- headers.Add(k, v)
- }
- }
-}
-
-type key int // used for context keys
-
-var infoKey key
-
-// AuthenticatorInterface is the interface implemented by BasicAuth
-// and DigestAuth authenticators.
-//
-// Deprecated: this interface is not coherent. New code should define
-// and use your own interfaces with a required subset of authenticator
-// methods.
-type AuthenticatorInterface interface {
- // NewContext returns a new context carrying authentication
- // information extracted from the request.
- NewContext(ctx context.Context, r *http.Request) context.Context
-
- // Wrap returns an http.HandlerFunc which wraps
- // AuthenticatedHandlerFunc with this authenticator's
- // authentication checks.
- Wrap(AuthenticatedHandlerFunc) http.HandlerFunc
-}
-
-// FromContext returns authentication information from the context or
-// nil if no such information present.
-func FromContext(ctx context.Context) *Info {
- info, ok := ctx.Value(infoKey).(*Info)
- if !ok {
- return nil
- }
- return info
-}
-
-// AuthUsernameHeader is the header set by JustCheck functions. It
-// contains an authenticated username (if authentication was
-// successful).
-const AuthUsernameHeader = "X-Authenticated-Username"
-
-// JustCheck returns a new http.HandlerFunc, which requires
-// authenticator to successfully authenticate a user before calling
-// wrapped http.HandlerFunc.
-func JustCheck(auth AuthenticatorInterface, wrapped http.HandlerFunc) http.HandlerFunc {
- return auth.Wrap(func(w http.ResponseWriter, ar *AuthenticatedRequest) {
- ar.Header.Set(AuthUsernameHeader, ar.Username)
- wrapped(w, &ar.Request)
- })
-}
diff --git a/vendor/github.com/abbot/go-http-auth/basic.go b/vendor/github.com/abbot/go-http-auth/basic.go
deleted file mode 100644
index f328a328..00000000
--- a/vendor/github.com/abbot/go-http-auth/basic.go
+++ /dev/null
@@ -1,161 +0,0 @@
-package auth
-
-import (
- "bytes"
- "context"
- "crypto/sha1"
- "crypto/subtle"
- "encoding/base64"
- "errors"
- "net/http"
- "strings"
-
- "golang.org/x/crypto/bcrypt"
-)
-
-type compareFunc func(hashedPassword, password []byte) error
-
-var (
- errMismatchedHashAndPassword = errors.New("mismatched hash and password")
-
- compareFuncs = []struct {
- prefix string
- compare compareFunc
- }{
- {"", compareMD5HashAndPassword}, // default compareFunc
- {"{SHA}", compareShaHashAndPassword},
- // Bcrypt is complicated. According to crypt(3) from
- // crypt_blowfish version 1.3 (fetched from
- // http://www.openwall.com/crypt/crypt_blowfish-1.3.tar.gz), there
- // are three different has prefixes: "$2a$", used by versions up
- // to 1.0.4, and "$2x$" and "$2y$", used in all later
- // versions. "$2a$" has a known bug, "$2x$" was added as a
- // migration path for systems with "$2a$" prefix and still has a
- // bug, and only "$2y$" should be used by modern systems. The bug
- // has something to do with handling of 8-bit characters. Since
- // both "$2a$" and "$2x$" are deprecated, we are handling them the
- // same way as "$2y$", which will yield correct results for 7-bit
- // character passwords, but is wrong for 8-bit character
- // passwords. You have to upgrade to "$2y$" if you want sant 8-bit
- // character password support with bcrypt. To add to the mess,
- // OpenBSD 5.5. introduced "$2b$" prefix, which behaves exactly
- // like "$2y$" according to the same source.
- {"$2a$", bcrypt.CompareHashAndPassword},
- {"$2b$", bcrypt.CompareHashAndPassword},
- {"$2x$", bcrypt.CompareHashAndPassword},
- {"$2y$", bcrypt.CompareHashAndPassword},
- }
-)
-
-// BasicAuth is an authenticator implementation for 'Basic' HTTP
-// Authentication scheme (RFC 7617).
-type BasicAuth struct {
- Realm string
- Secrets SecretProvider
- // Headers used by authenticator. Set to ProxyHeaders to use with
- // proxy server. When nil, NormalHeaders are used.
- Headers *Headers
-}
-
-// check that BasicAuth implements AuthenticatorInterface
-var _ = (AuthenticatorInterface)((*BasicAuth)(nil))
-
-// CheckAuth checks the username/password combination from the
-// request. Returns either an empty string (authentication failed) or
-// the name of the authenticated user.
-func (a *BasicAuth) CheckAuth(r *http.Request) string {
- user, password, ok := r.BasicAuth()
- if !ok {
- return ""
- }
-
- secret := a.Secrets(user, a.Realm)
- if secret == "" {
- return ""
- }
-
- if !CheckSecret(password, secret) {
- return ""
- }
-
- return user
-}
-
-// CheckSecret returns true if the password matches the encrypted
-// secret.
-func CheckSecret(password, secret string) bool {
- compare := compareFuncs[0].compare
- for _, cmp := range compareFuncs[1:] {
- if strings.HasPrefix(secret, cmp.prefix) {
- compare = cmp.compare
- break
- }
- }
- return compare([]byte(secret), []byte(password)) == nil
-}
-
-func compareShaHashAndPassword(hashedPassword, password []byte) error {
- d := sha1.New()
- d.Write(password)
- if subtle.ConstantTimeCompare(hashedPassword[5:], []byte(base64.StdEncoding.EncodeToString(d.Sum(nil)))) != 1 {
- return errMismatchedHashAndPassword
- }
- return nil
-}
-
-func compareMD5HashAndPassword(hashedPassword, password []byte) error {
- parts := bytes.SplitN(hashedPassword, []byte("$"), 4)
- if len(parts) != 4 {
- return errMismatchedHashAndPassword
- }
- magic := []byte("$" + string(parts[1]) + "$")
- salt := parts[2]
- if subtle.ConstantTimeCompare(hashedPassword, MD5Crypt(password, salt, magic)) != 1 {
- return errMismatchedHashAndPassword
- }
- return nil
-}
-
-// RequireAuth is an http.HandlerFunc for BasicAuth which initiates
-// the authentication process (or requires reauthentication).
-func (a *BasicAuth) RequireAuth(w http.ResponseWriter, r *http.Request) {
- w.Header().Set(contentType, a.Headers.V().UnauthContentType)
- w.Header().Set(a.Headers.V().Authenticate, `Basic realm="`+a.Realm+`"`)
- w.WriteHeader(a.Headers.V().UnauthCode)
- w.Write([]byte(a.Headers.V().UnauthResponse))
-}
-
-// Wrap returns an http.HandlerFunc, which wraps
-// AuthenticatedHandlerFunc with this BasicAuth authenticator's
-// authentication checks. Once the request contains valid credentials,
-// it calls wrapped AuthenticatedHandlerFunc.
-//
-// Deprecated: new code should use NewContext instead.
-func (a *BasicAuth) Wrap(wrapped AuthenticatedHandlerFunc) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- if username := a.CheckAuth(r); username == "" {
- a.RequireAuth(w, r)
- } else {
- ar := &AuthenticatedRequest{Request: *r, Username: username}
- wrapped(w, ar)
- }
- }
-}
-
-// NewContext returns a context carrying authentication information for the request.
-func (a *BasicAuth) NewContext(ctx context.Context, r *http.Request) context.Context {
- info := &Info{Username: a.CheckAuth(r), ResponseHeaders: make(http.Header)}
- info.Authenticated = (info.Username != "")
- if !info.Authenticated {
- info.ResponseHeaders.Set(a.Headers.V().Authenticate, `Basic realm="`+a.Realm+`"`)
- }
- return context.WithValue(ctx, infoKey, info)
-}
-
-// NewBasicAuthenticator returns a BasicAuth initialized with provided
-// realm and secrets.
-//
-// Deprecated: new code should construct BasicAuth values directly.
-func NewBasicAuthenticator(realm string, secrets SecretProvider) *BasicAuth {
- return &BasicAuth{Realm: realm, Secrets: secrets}
-}
diff --git a/vendor/github.com/abbot/go-http-auth/digest.go b/vendor/github.com/abbot/go-http-auth/digest.go
deleted file mode 100644
index 88ac4bd4..00000000
--- a/vendor/github.com/abbot/go-http-auth/digest.go
+++ /dev/null
@@ -1,288 +0,0 @@
-package auth
-
-import (
- "context"
- "crypto/subtle"
- "fmt"
- "net/http"
- "net/url"
- "sort"
- "strconv"
- "strings"
- "sync"
- "time"
-)
-
-type digestClient struct {
- nc uint64
- lastSeen int64
-}
-
-// DigestAuth is an authenticator implementation for 'Digest' HTTP Authentication scheme (RFC 7616).
-//
-// Note: this implementation was written following now deprecated RFC
-// 2617, and supports only MD5 algorithm.
-//
-// TODO: Add support for SHA-256 and SHA-512/256 algorithms.
-type DigestAuth struct {
- Realm string
- Opaque string
- Secrets SecretProvider
- PlainTextSecrets bool
- IgnoreNonceCount bool
- // Headers used by authenticator. Set to ProxyHeaders to use with
- // proxy server. When nil, NormalHeaders are used.
- Headers *Headers
-
- /*
- Approximate size of Client's Cache. When actual number of
- tracked client nonces exceeds
- ClientCacheSize+ClientCacheTolerance, ClientCacheTolerance*2
- older entries are purged.
- */
- ClientCacheSize int
- ClientCacheTolerance int
-
- clients map[string]*digestClient
- mutex sync.RWMutex
-}
-
-// check that DigestAuth implements AuthenticatorInterface
-var _ = (AuthenticatorInterface)((*DigestAuth)(nil))
-
-type digestCacheEntry struct {
- nonce string
- lastSeen int64
-}
-
-type digestCache []digestCacheEntry
-
-func (c digestCache) Less(i, j int) bool {
- return c[i].lastSeen < c[j].lastSeen
-}
-
-func (c digestCache) Len() int {
- return len(c)
-}
-
-func (c digestCache) Swap(i, j int) {
- c[i], c[j] = c[j], c[i]
-}
-
-// Purge removes count oldest entries from DigestAuth.clients
-func (da *DigestAuth) Purge(count int) {
- da.mutex.Lock()
- da.purgeLocked(count)
- da.mutex.Unlock()
-}
-
-func (da *DigestAuth) purgeLocked(count int) {
- entries := make([]digestCacheEntry, 0, len(da.clients))
- for nonce, client := range da.clients {
- entries = append(entries, digestCacheEntry{nonce, client.lastSeen})
- }
- cache := digestCache(entries)
- sort.Sort(cache)
- for _, client := range cache[:count] {
- delete(da.clients, client.nonce)
- }
-}
-
-// RequireAuth is an http.HandlerFunc which initiates the
-// authentication process (or requires reauthentication).
-func (da *DigestAuth) RequireAuth(w http.ResponseWriter, r *http.Request) {
- da.mutex.RLock()
- clientsLen := len(da.clients)
- da.mutex.RUnlock()
-
- if clientsLen > da.ClientCacheSize+da.ClientCacheTolerance {
- da.Purge(da.ClientCacheTolerance * 2)
- }
- nonce := RandomKey()
-
- da.mutex.Lock()
- da.clients[nonce] = &digestClient{nc: 0, lastSeen: time.Now().UnixNano()}
- da.mutex.Unlock()
-
- da.mutex.RLock()
- w.Header().Set(contentType, da.Headers.V().UnauthContentType)
- w.Header().Set(da.Headers.V().Authenticate,
- fmt.Sprintf(`Digest realm="%s", nonce="%s", opaque="%s", algorithm=MD5, qop="auth"`,
- da.Realm, nonce, da.Opaque))
- w.WriteHeader(da.Headers.V().UnauthCode)
- w.Write([]byte(da.Headers.V().UnauthResponse))
- da.mutex.RUnlock()
-}
-
-// DigestAuthParams parses Authorization header from the
-// http.Request. Returns a map of auth parameters or nil if the header
-// is not a valid parsable Digest auth header.
-func DigestAuthParams(authorization string) map[string]string {
- s := strings.SplitN(authorization, " ", 2)
- if len(s) != 2 || s[0] != "Digest" {
- return nil
- }
-
- return ParsePairs(s[1])
-}
-
-// CheckAuth checks whether the request contains valid authentication
-// data. Returns a pair of username, authinfo, where username is the
-// name of the authenticated user or an empty string and authinfo is
-// the contents for the optional Authentication-Info response header.
-func (da *DigestAuth) CheckAuth(r *http.Request) (username string, authinfo *string) {
- da.mutex.RLock()
- defer da.mutex.RUnlock()
- username = ""
- authinfo = nil
- auth := DigestAuthParams(r.Header.Get(da.Headers.V().Authorization))
- if auth == nil {
- return "", nil
- }
- // RFC2617 Section 3.2.1 specifies that unset value of algorithm in
- // WWW-Authenticate Response header should be treated as
- // "MD5". According to section 3.2.2 the "algorithm" value in
- // subsequent Request Authorization header must be set to whatever
- // was supplied in the WWW-Authenticate Response header. This
- // implementation always returns an algorithm in WWW-Authenticate
- // header, however there seems to be broken clients in the wild
- // which do not set the algorithm. Assume the unset algorithm in
- // Authorization header to be equal to MD5.
- if _, ok := auth["algorithm"]; !ok {
- auth["algorithm"] = "MD5"
- }
- if da.Opaque != auth["opaque"] || auth["algorithm"] != "MD5" || auth["qop"] != "auth" {
- return "", nil
- }
-
- // Check if the requested URI matches auth header
- if r.RequestURI != auth["uri"] {
- // We allow auth["uri"] to be a full path prefix of request-uri
- // for some reason lost in history, which is probably wrong, but
- // used to be like that for quite some time
- // (https://tools.ietf.org/html/rfc2617#section-3.2.2 explicitly
- // says that auth["uri"] is the request-uri).
- //
- // TODO: make an option to allow only strict checking.
- switch u, err := url.Parse(auth["uri"]); {
- case err != nil:
- return "", nil
- case r.URL == nil:
- return "", nil
- case len(u.Path) > len(r.URL.Path):
- return "", nil
- case !strings.HasPrefix(r.URL.Path, u.Path):
- return "", nil
- }
- }
-
- HA1 := da.Secrets(auth["username"], da.Realm)
- if da.PlainTextSecrets {
- HA1 = H(auth["username"] + ":" + da.Realm + ":" + HA1)
- }
- HA2 := H(r.Method + ":" + auth["uri"])
- KD := H(strings.Join([]string{HA1, auth["nonce"], auth["nc"], auth["cnonce"], auth["qop"], HA2}, ":"))
-
- if subtle.ConstantTimeCompare([]byte(KD), []byte(auth["response"])) != 1 {
- return "", nil
- }
-
- // At this point crypto checks are completed and validated.
- // Now check if the session is valid.
-
- nc, err := strconv.ParseUint(auth["nc"], 16, 64)
- if err != nil {
- return "", nil
- }
-
- client, ok := da.clients[auth["nonce"]]
- if !ok {
- return "", nil
- }
- if client.nc != 0 && client.nc >= nc && !da.IgnoreNonceCount {
- return "", nil
- }
- client.nc = nc
- client.lastSeen = time.Now().UnixNano()
-
- respHA2 := H(":" + auth["uri"])
- rspauth := H(strings.Join([]string{HA1, auth["nonce"], auth["nc"], auth["cnonce"], auth["qop"], respHA2}, ":"))
-
- info := fmt.Sprintf(`qop="auth", rspauth="%s", cnonce="%s", nc="%s"`, rspauth, auth["cnonce"], auth["nc"])
- return auth["username"], &info
-}
-
-// Default values for ClientCacheSize and ClientCacheTolerance for DigestAuth
-const (
- DefaultClientCacheSize = 1000
- DefaultClientCacheTolerance = 100
-)
-
-// Wrap returns an http.HandlerFunc wraps AuthenticatedHandlerFunc
-// with this DigestAuth authentication checks. Once the request
-// contains valid credentials, it calls wrapped
-// AuthenticatedHandlerFunc.
-//
-// Deprecated: new code should use NewContext instead.
-func (da *DigestAuth) Wrap(wrapped AuthenticatedHandlerFunc) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- if username, authinfo := da.CheckAuth(r); username == "" {
- da.RequireAuth(w, r)
- } else {
- ar := &AuthenticatedRequest{Request: *r, Username: username}
- if authinfo != nil {
- w.Header().Set(da.Headers.V().AuthInfo, *authinfo)
- }
- wrapped(w, ar)
- }
- }
-}
-
-// JustCheck returns a new http.HandlerFunc, which requires
-// DigestAuth to successfully authenticate a user before calling
-// wrapped http.HandlerFunc.
-//
-// Authenticated Username is passed as an extra
-// X-Authenticated-Username header to the wrapped HandlerFunc.
-func (da *DigestAuth) JustCheck(wrapped http.HandlerFunc) http.HandlerFunc {
- return da.Wrap(func(w http.ResponseWriter, ar *AuthenticatedRequest) {
- ar.Header.Set(AuthUsernameHeader, ar.Username)
- wrapped(w, &ar.Request)
- })
-}
-
-// NewContext returns a context carrying authentication information for the request.
-func (da *DigestAuth) NewContext(ctx context.Context, r *http.Request) context.Context {
- username, authinfo := da.CheckAuth(r)
- da.mutex.Lock()
- defer da.mutex.Unlock()
- info := &Info{Username: username, ResponseHeaders: make(http.Header)}
- if username != "" {
- info.Authenticated = true
- info.ResponseHeaders.Set(da.Headers.V().AuthInfo, *authinfo)
- } else {
- // return back digest WWW-Authenticate header
- if len(da.clients) > da.ClientCacheSize+da.ClientCacheTolerance {
- da.purgeLocked(da.ClientCacheTolerance * 2)
- }
- nonce := RandomKey()
- da.clients[nonce] = &digestClient{nc: 0, lastSeen: time.Now().UnixNano()}
- info.ResponseHeaders.Set(da.Headers.V().Authenticate,
- fmt.Sprintf(`Digest realm="%s", nonce="%s", opaque="%s", algorithm=MD5, qop="auth"`,
- da.Realm, nonce, da.Opaque))
- }
- return context.WithValue(ctx, infoKey, info)
-}
-
-// NewDigestAuthenticator generates a new DigestAuth object
-func NewDigestAuthenticator(realm string, secrets SecretProvider) *DigestAuth {
- da := &DigestAuth{
- Opaque: RandomKey(),
- Realm: realm,
- Secrets: secrets,
- PlainTextSecrets: false,
- ClientCacheSize: DefaultClientCacheSize,
- ClientCacheTolerance: DefaultClientCacheTolerance,
- clients: map[string]*digestClient{}}
- return da
-}
diff --git a/vendor/github.com/abbot/go-http-auth/go.mod b/vendor/github.com/abbot/go-http-auth/go.mod
deleted file mode 100644
index 80cdc218..00000000
--- a/vendor/github.com/abbot/go-http-auth/go.mod
+++ /dev/null
@@ -1,5 +0,0 @@
-module github.com/abbot/go-http-auth
-
-go 1.14
-
-require golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
diff --git a/vendor/github.com/abbot/go-http-auth/go.sum b/vendor/github.com/abbot/go-http-auth/go.sum
deleted file mode 100644
index 814b1a38..00000000
--- a/vendor/github.com/abbot/go-http-auth/go.sum
+++ /dev/null
@@ -1,8 +0,0 @@
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/vendor/github.com/abbot/go-http-auth/md5crypt.go b/vendor/github.com/abbot/go-http-auth/md5crypt.go
deleted file mode 100644
index ed7ccc37..00000000
--- a/vendor/github.com/abbot/go-http-auth/md5crypt.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package auth
-
-import "crypto/md5"
-
-const itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
-
-var md5CryptSwaps = [16]int{12, 6, 0, 13, 7, 1, 14, 8, 2, 15, 9, 3, 5, 10, 4, 11}
-
-// MD5Crypt is the MD5 password crypt implementation.
-func MD5Crypt(password, salt, magic []byte) []byte {
- d := md5.New()
-
- d.Write(password)
- d.Write(magic)
- d.Write(salt)
-
- d2 := md5.New()
- d2.Write(password)
- d2.Write(salt)
- d2.Write(password)
-
- for i, mixin := 0, d2.Sum(nil); i < len(password); i++ {
- d.Write([]byte{mixin[i%16]})
- }
-
- for i := len(password); i != 0; i >>= 1 {
- if i&1 == 0 {
- d.Write([]byte{password[0]})
- } else {
- d.Write([]byte{0})
- }
- }
-
- final := d.Sum(nil)
-
- for i := 0; i < 1000; i++ {
- d2 := md5.New()
- if i&1 == 0 {
- d2.Write(final)
- } else {
- d2.Write(password)
- }
-
- if i%3 != 0 {
- d2.Write(salt)
- }
-
- if i%7 != 0 {
- d2.Write(password)
- }
-
- if i&1 == 0 {
- d2.Write(password)
- } else {
- d2.Write(final)
- }
- final = d2.Sum(nil)
- }
-
- result := make([]byte, 0, 22)
- v := uint(0)
- bits := uint(0)
- for _, i := range md5CryptSwaps {
- v |= (uint(final[i]) << bits)
- for bits = bits + 8; bits > 6; bits -= 6 {
- result = append(result, itoa64[v&0x3f])
- v >>= 6
- }
- }
- result = append(result, itoa64[v&0x3f])
-
- return append(append(append(magic, salt...), '$'), result...)
-}
diff --git a/vendor/github.com/abbot/go-http-auth/misc.go b/vendor/github.com/abbot/go-http-auth/misc.go
deleted file mode 100644
index c4380255..00000000
--- a/vendor/github.com/abbot/go-http-auth/misc.go
+++ /dev/null
@@ -1,146 +0,0 @@
-package auth
-
-import (
- "bytes"
- "crypto/md5"
- "crypto/rand"
- "encoding/base64"
- "fmt"
- "net/http"
- "strings"
-)
-
-// RandomKey returns a random 16-byte base64 alphabet string
-func RandomKey() string {
- k := make([]byte, 12)
- for bytes := 0; bytes < len(k); {
- n, err := rand.Read(k[bytes:])
- if err != nil {
- panic("rand.Read() failed")
- }
- bytes += n
- }
- return base64.StdEncoding.EncodeToString(k)
-}
-
-// H function for MD5 algorithm (returns a lower-case hex MD5 digest)
-func H(data string) string {
- digest := md5.New()
- digest.Write([]byte(data))
- return fmt.Sprintf("%x", digest.Sum(nil))
-}
-
-// ParseList parses a comma-separated list of values as described by
-// RFC 2068 and returns list elements.
-//
-// Lifted from https://code.google.com/p/gorilla/source/browse/http/parser/parser.go
-// which was ported from urllib2.parse_http_list, from the Python
-// standard library.
-func ParseList(value string) []string {
- var list []string
- var escape, quote bool
- b := new(bytes.Buffer)
- for _, r := range value {
- switch {
- case escape:
- b.WriteRune(r)
- escape = false
- case quote:
- if r == '\\' {
- escape = true
- } else {
- if r == '"' {
- quote = false
- }
- b.WriteRune(r)
- }
- case r == ',':
- list = append(list, strings.TrimSpace(b.String()))
- b.Reset()
- case r == '"':
- quote = true
- b.WriteRune(r)
- default:
- b.WriteRune(r)
- }
- }
- // Append last part.
- if s := b.String(); s != "" {
- list = append(list, strings.TrimSpace(s))
- }
- return list
-}
-
-// ParsePairs extracts key/value pairs from a comma-separated list of
-// values as described by RFC 2068 and returns a map[key]value. The
-// resulting values are unquoted. If a list element doesn't contain a
-// "=", the key is the element itself and the value is an empty
-// string.
-//
-// Lifted from https://code.google.com/p/gorilla/source/browse/http/parser/parser.go
-func ParsePairs(value string) map[string]string {
- m := make(map[string]string)
- for _, pair := range ParseList(strings.TrimSpace(value)) {
- switch i := strings.Index(pair, "="); {
- case i < 0:
- // No '=' in pair, treat whole string as a 'key'.
- m[pair] = ""
- case i == len(pair)-1:
- // Malformed pair ('key=' with no value), keep key with empty value.
- m[pair[:i]] = ""
- default:
- v := pair[i+1:]
- if v[0] == '"' && v[len(v)-1] == '"' {
- // Unquote it.
- v = v[1 : len(v)-1]
- }
- m[pair[:i]] = v
- }
- }
- return m
-}
-
-// Headers contains header and error codes used by authenticator.
-type Headers struct {
- Authenticate string // WWW-Authenticate
- Authorization string // Authorization
- AuthInfo string // Authentication-Info
- UnauthCode int // 401
- UnauthContentType string // text/plain
- UnauthResponse string // Unauthorized.
-}
-
-// V returns NormalHeaders when h is nil, or h otherwise. Allows to
-// use uninitialized *Headers values in structs.
-func (h *Headers) V() *Headers {
- if h == nil {
- return NormalHeaders
- }
- return h
-}
-
-var (
- // NormalHeaders are the regular Headers used by an HTTP Server for
- // request authentication.
- NormalHeaders = &Headers{
- Authenticate: "WWW-Authenticate",
- Authorization: "Authorization",
- AuthInfo: "Authentication-Info",
- UnauthCode: http.StatusUnauthorized,
- UnauthContentType: "text/plain",
- UnauthResponse: fmt.Sprintf("%d %s\n", http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized)),
- }
-
- // ProxyHeaders are Headers used by an HTTP Proxy server for proxy
- // access authentication.
- ProxyHeaders = &Headers{
- Authenticate: "Proxy-Authenticate",
- Authorization: "Proxy-Authorization",
- AuthInfo: "Proxy-Authentication-Info",
- UnauthCode: http.StatusProxyAuthRequired,
- UnauthContentType: "text/plain",
- UnauthResponse: fmt.Sprintf("%d %s\n", http.StatusProxyAuthRequired, http.StatusText(http.StatusProxyAuthRequired)),
- }
-)
-
-const contentType = "Content-Type"
diff --git a/vendor/github.com/abbot/go-http-auth/test.htdigest b/vendor/github.com/abbot/go-http-auth/test.htdigest
deleted file mode 100644
index 6c8c75b4..00000000
--- a/vendor/github.com/abbot/go-http-auth/test.htdigest
+++ /dev/null
@@ -1 +0,0 @@
-test:example.com:aa78524fceb0e50fd8ca96dd818b8cf9
diff --git a/vendor/github.com/abbot/go-http-auth/test.htpasswd b/vendor/github.com/abbot/go-http-auth/test.htpasswd
deleted file mode 100644
index 4844a3cc..00000000
--- a/vendor/github.com/abbot/go-http-auth/test.htpasswd
+++ /dev/null
@@ -1,4 +0,0 @@
-test:{SHA}qvTGHdzF6KLavt4PO0gs2a6pQ00=
-test2:$apr1$a0j62R97$mYqFkloXH0/UOaUnAiV2b0
-test16:$apr1$JI4wh3am$AmhephVqLTUyAVpFQeHZC0
-test3:$2y$05$ih3C91zUBSTFcAh2mQnZYuob0UOZVEf16wl/ukgjDhjvj.xgM1WwS
diff --git a/vendor/github.com/abbot/go-http-auth/users.go b/vendor/github.com/abbot/go-http-auth/users.go
deleted file mode 100644
index ba032fe9..00000000
--- a/vendor/github.com/abbot/go-http-auth/users.go
+++ /dev/null
@@ -1,151 +0,0 @@
-package auth
-
-import (
- "encoding/csv"
- "os"
- "sync"
-)
-
-// SecretProvider is used by authenticators. Takes user name and realm
-// as an argument, returns secret required for authentication (HA1 for
-// digest authentication, properly encrypted password for basic).
-//
-// Returning an empty string means failing the authentication.
-type SecretProvider func(user, realm string) string
-
-// File handles automatic file reloading on changes.
-type File struct {
- Path string
- Info os.FileInfo
- /* must be set in inherited types during initialization */
- Reload func()
- mu sync.Mutex
-}
-
-// ReloadIfNeeded checks file Stat and calls Reload() if any changes
-// were detected. File mutex is Locked for the duration of Reload()
-// call.
-//
-// This function will panic() if Stat fails.
-func (f *File) ReloadIfNeeded() {
- info, err := os.Stat(f.Path)
- if err != nil {
- panic(err)
- }
- f.mu.Lock()
- defer f.mu.Unlock()
- if f.Info == nil || f.Info.ModTime() != info.ModTime() {
- f.Info = info
- f.Reload()
- }
-}
-
-// HtdigestFile is a File holding htdigest authentication data.
-type HtdigestFile struct {
- // File is used for automatic reloading of the authentication data.
- File
- // Users is a map of realms to users to HA1 digests.
- Users map[string]map[string]string
- mu sync.RWMutex
-}
-
-func reloadHTDigest(hf *HtdigestFile) {
- r, err := os.Open(hf.Path)
- if err != nil {
- panic(err)
- }
- reader := csv.NewReader(r)
- reader.Comma = ':'
- reader.Comment = '#'
- reader.TrimLeadingSpace = true
-
- records, err := reader.ReadAll()
- if err != nil {
- panic(err)
- }
-
- hf.mu.Lock()
- defer hf.mu.Unlock()
- hf.Users = make(map[string]map[string]string)
- for _, record := range records {
- _, exists := hf.Users[record[1]]
- if !exists {
- hf.Users[record[1]] = make(map[string]string)
- }
- hf.Users[record[1]][record[0]] = record[2]
- }
-}
-
-// HtdigestFileProvider is a SecretProvider implementation based on
-// htdigest-formated files. It will automatically reload htdigest file
-// on changes. It panics on syntax errors in htdigest files.
-func HtdigestFileProvider(filename string) SecretProvider {
- hf := &HtdigestFile{File: File{Path: filename}}
- hf.Reload = func() { reloadHTDigest(hf) }
- return func(user, realm string) string {
- hf.ReloadIfNeeded()
- hf.mu.RLock()
- defer hf.mu.RUnlock()
- _, exists := hf.Users[realm]
- if !exists {
- return ""
- }
- digest, exists := hf.Users[realm][user]
- if !exists {
- return ""
- }
- return digest
- }
-}
-
-// HtpasswdFile is a File holding basic authentication data.
-type HtpasswdFile struct {
- // File is used for automatic reloading of the authentication data.
- File
- // Users is a map of users to their secrets (salted encrypted
- // passwords).
- Users map[string]string
- mu sync.RWMutex
-}
-
-func reloadHTPasswd(h *HtpasswdFile) {
- r, err := os.Open(h.Path)
- if err != nil {
- panic(err)
- }
- reader := csv.NewReader(r)
- reader.Comma = ':'
- reader.Comment = '#'
- reader.TrimLeadingSpace = true
-
- records, err := reader.ReadAll()
- if err != nil {
- panic(err)
- }
-
- h.mu.Lock()
- defer h.mu.Unlock()
- h.Users = make(map[string]string)
- for _, record := range records {
- h.Users[record[0]] = record[1]
- }
-}
-
-// HtpasswdFileProvider is a SecretProvider implementation based on
-// htpasswd-formated files. It will automatically reload htpasswd file
-// on changes. It panics on syntax errors in htpasswd files. Realm
-// argument of the SecretProvider is ignored.
-func HtpasswdFileProvider(filename string) SecretProvider {
- h := &HtpasswdFile{File: File{Path: filename}}
- h.Reload = func() { reloadHTPasswd(h) }
- return func(user, realm string) string {
- h.ReloadIfNeeded()
- h.mu.RLock()
- password, exists := h.Users[user]
- h.mu.RUnlock()
- if !exists {
- return ""
- }
- return password
- }
-}
diff --git a/vendor/github.com/tredoe/osutil/AUTHORS.md b/vendor/github.com/tredoe/osutil/AUTHORS.md
new file mode 100644
index 00000000..518f1942
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/AUTHORS.md
@@ -0,0 +1,16 @@
+# Authors
+
+This is the official list of authors for copyright purposes.
+This file is distinct from the 'CONTRIBUTORS' file. See the latter for an explanation.
+
+Names should be added to this file as:
+
+ Name or Organization / (url address)
+
+(The email address is not required for organizations)
+
+Please keep the list sorted.
+
+## Code
+
+* Jonas mg (https://github.com/tredoe)
diff --git a/vendor/github.com/tredoe/osutil/CONTRIBUTORS.md b/vendor/github.com/tredoe/osutil/CONTRIBUTORS.md
new file mode 100644
index 00000000..b630fff1
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/CONTRIBUTORS.md
@@ -0,0 +1,22 @@
+# Contributors
+
+This is the official list of people who can contribute (and typically
+have contributed) to the repository.
+
+The 'AUTHORS' file lists the copyright holders; this file lists people. For
+example, the employees of an organization are listed here but not in 'AUTHORS',
+because the organization holds the copyright.
+
+Names should be added to this file as:
+
+ Name / (url address)
+
+Please keep the list sorted.
+
+## Code
+
+* Jonas mg (https://github.com/tredoe)
+
+* DJ Gregor
+* Jeramey Crawford
+* Misha Seltzer (https://github.com/mishas)
diff --git a/vendor/github.com/tredoe/osutil/LICENSE-MPL.txt b/vendor/github.com/tredoe/osutil/LICENSE-MPL.txt
new file mode 100644
index 00000000..52d13511
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/LICENSE-MPL.txt
@@ -0,0 +1,374 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
+
diff --git a/vendor/github.com/tredoe/osutil/user/crypt/AUTHORS.md b/vendor/github.com/tredoe/osutil/user/crypt/AUTHORS.md
new file mode 100644
index 00000000..8eb23dd0
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/user/crypt/AUTHORS.md
@@ -0,0 +1,8 @@
+### Initial author
+
+[Jeramey Crawford](https://github.com/jeramey)
+
+### Other authors
+
+[Jonas mg](https://github.com/tredoe)
+
diff --git a/vendor/github.com/tredoe/osutil/user/crypt/LICENSE b/vendor/github.com/tredoe/osutil/user/crypt/LICENSE
new file mode 100644
index 00000000..c39e0de5
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/user/crypt/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2012, Jeramey Crawford
+Copyright (c) 2013, Jonas mg
+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.
+
+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
+HOLDER 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.
diff --git a/vendor/github.com/tredoe/osutil/user/crypt/README.md b/vendor/github.com/tredoe/osutil/user/crypt/README.md
new file mode 100644
index 00000000..cbcfb2e5
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/user/crypt/README.md
@@ -0,0 +1,25 @@
+crypt
+=====
+A password hashing library.
+
+The goal of crypt is to bring a library of many common and popular password
+hashing algorithms to Go and to provide a simple and consistent interface to
+each of them. As every hashing method is implemented in pure Go, this library
+should be as portable as Go itself.
+
+All hashing methods come with a test suite which verifies their operation
+against itself as well as the output of other password hashing implementations
+to ensure compatibility with them.
+
+I hope you find this library to be useful and easy to use!
+
+Note: forked from
+
+## Installation
+
+ go get github.com/tredoe/osutil/user/crypt
+
+## License
+
+The source files are distributed under a BSD-style license that can be found
+in the LICENSE file.
diff --git a/vendor/github.com/tredoe/osutil/user/crypt/apr1_crypt/apr1_crypt.go b/vendor/github.com/tredoe/osutil/user/crypt/apr1_crypt/apr1_crypt.go
new file mode 100644
index 00000000..bb367547
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/user/crypt/apr1_crypt/apr1_crypt.go
@@ -0,0 +1,62 @@
+// Copyright 2012, Jeramey Crawford
+// Copyright 2013, Jonas mg
+// All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+// Package apr1_crypt implements the standard Unix MD5-crypt algorithm created
+// by Poul-Henning Kamp for FreeBSD, and modified by the Apache project.
+//
+// The only change from MD5-crypt is the use of the magic constant "$apr1$"
+// instead of "$1$". The algorithms are otherwise identical.
+package apr1_crypt
+
+import (
+ "github.com/tredoe/osutil/user/crypt"
+ "github.com/tredoe/osutil/user/crypt/common"
+ "github.com/tredoe/osutil/user/crypt/md5_crypt"
+)
+
+func init() {
+ crypt.RegisterCrypt(crypt.APR1, New, MagicPrefix)
+}
+
+const (
+ MagicPrefix = "$apr1$"
+ SaltLenMin = 1
+ SaltLenMax = 8
+ RoundsDefault = 1000
+)
+
+var md5Crypt = md5_crypt.New()
+
+func init() {
+ md5Crypt.SetSalt(GetSalt())
+}
+
+type crypter struct{ Salt common.Salt }
+
+// New returns a new crypt.Crypter computing the variant "apr1" of MD5-crypt
+func New() crypt.Crypter { return &crypter{common.Salt{}} }
+
+func (c *crypter) Generate(key, salt []byte) (string, error) {
+ return md5Crypt.Generate(key, salt)
+}
+
+func (c *crypter) Verify(hashedKey string, key []byte) error {
+ return md5Crypt.Verify(hashedKey, key)
+}
+
+func (c *crypter) Cost(hashedKey string) (int, error) { return RoundsDefault, nil }
+
+func (c *crypter) SetSalt(salt common.Salt) {}
+
+func GetSalt() common.Salt {
+ return common.Salt{
+ MagicPrefix: []byte(MagicPrefix),
+ SaltLenMin: SaltLenMin,
+ SaltLenMax: SaltLenMax,
+ RoundsDefault: RoundsDefault,
+ }
+}
diff --git a/vendor/github.com/tredoe/osutil/user/crypt/common/base64.go b/vendor/github.com/tredoe/osutil/user/crypt/common/base64.go
new file mode 100644
index 00000000..ed057d5c
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/user/crypt/common/base64.go
@@ -0,0 +1,60 @@
+// Copyright 2012, Jeramey Crawford
+// Copyright 2013, Jonas mg
+// All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+package common
+
+const alphabet = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+
+// Base64_24Bit is a variant of Base64 encoding, commonly used with password
+// hashing algorithms to encode the result of their checksum output.
+//
+// The algorithm operates on up to 3 bytes at a time, encoding the following
+// 6-bit sequences into up to 4 hash64 ASCII bytes.
+//
+// 1. Bottom 6 bits of the first byte
+// 2. Top 2 bits of the first byte, and bottom 4 bits of the second byte.
+// 3. Top 4 bits of the second byte, and bottom 2 bits of the third byte.
+// 4. Top 6 bits of the third byte.
+//
+// This encoding method does not emit padding bytes as Base64 does.
+func Base64_24Bit(src []byte) (hash []byte) {
+ if len(src) == 0 {
+ return []byte{} // TODO: return nil
+ }
+
+ hashSize := (len(src) * 8) / 6
+ if (len(src) % 6) != 0 {
+ hashSize += 1
+ }
+ hash = make([]byte, hashSize)
+
+ dst := hash
+ for len(src) > 0 {
+ switch len(src) {
+ default:
+ dst[0] = alphabet[src[0]&0x3f]
+ dst[1] = alphabet[((src[0]>>6)|(src[1]<<2))&0x3f]
+ dst[2] = alphabet[((src[1]>>4)|(src[2]<<4))&0x3f]
+ dst[3] = alphabet[(src[2]>>2)&0x3f]
+ src = src[3:]
+ dst = dst[4:]
+ case 2:
+ dst[0] = alphabet[src[0]&0x3f]
+ dst[1] = alphabet[((src[0]>>6)|(src[1]<<2))&0x3f]
+ dst[2] = alphabet[(src[1]>>4)&0x3f]
+ src = src[2:]
+ dst = dst[3:]
+ case 1:
+ dst[0] = alphabet[src[0]&0x3f]
+ dst[1] = alphabet[(src[0]>>6)&0x3f]
+ src = src[1:]
+ dst = dst[2:]
+ }
+ }
+
+ return
+}
diff --git a/vendor/github.com/tredoe/osutil/user/crypt/common/doc.go b/vendor/github.com/tredoe/osutil/user/crypt/common/doc.go
new file mode 100644
index 00000000..8eb6aff2
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/user/crypt/common/doc.go
@@ -0,0 +1,13 @@
+// Copyright 2012, Jeramey Crawford
+// Copyright 2013, Jonas mg
+// All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+// Package common contains routines used by multiple password hashing
+// algorithms.
+//
+// Generally, you will never import this package directly. Many of the
+// *_crypt packages will import this package if they require it.
+package common
diff --git a/vendor/github.com/tredoe/osutil/user/crypt/common/salt.go b/vendor/github.com/tredoe/osutil/user/crypt/common/salt.go
new file mode 100644
index 00000000..ee38851b
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/user/crypt/common/salt.go
@@ -0,0 +1,105 @@
+// Copyright 2012, Jeramey Crawford
+// Copyright 2013, Jonas mg
+// All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+package common
+
+import (
+ "crypto/rand"
+ "errors"
+ "strconv"
+)
+
+var (
+ ErrSaltPrefix = errors.New("invalid magic prefix")
+ ErrSaltFormat = errors.New("invalid salt format")
+ ErrSaltRounds = errors.New("invalid rounds")
+)
+
+// Salt represents a salt.
+type Salt struct {
+ MagicPrefix []byte
+
+ SaltLenMin int
+ SaltLenMax int
+
+ RoundsMin int
+ RoundsMax int
+ RoundsDefault int
+}
+
+// Generate generates a random salt of a given length.
+//
+// The length is set thus:
+//
+// length > SaltLenMax: length = SaltLenMax
+// length < SaltLenMin: length = SaltLenMin
+func (s *Salt) Generate(length int) []byte {
+ if length > s.SaltLenMax {
+ length = s.SaltLenMax
+ } else if length < s.SaltLenMin {
+ length = s.SaltLenMin
+ }
+
+ saltLen := (length * 6 / 8)
+ if (length*6)%8 != 0 {
+ saltLen++
+ }
+ salt := make([]byte, saltLen)
+ rand.Read(salt)
+
+ out := make([]byte, len(s.MagicPrefix)+length)
+ copy(out, s.MagicPrefix)
+ copy(out[len(s.MagicPrefix):], Base64_24Bit(salt))
+ return out
+}
+
+// GenerateWRounds creates a random salt with the random bytes being of the
+// length provided, and the rounds parameter set as specified.
+//
+// The parameters are set thus:
+//
+// length > SaltLenMax: length = SaltLenMax
+// length < SaltLenMin: length = SaltLenMin
+//
+// rounds < 0: rounds = RoundsDefault
+// rounds < RoundsMin: rounds = RoundsMin
+// rounds > RoundsMax: rounds = RoundsMax
+//
+// If rounds is equal to RoundsDefault, then the "rounds=" part of the salt is
+// removed.
+func (s *Salt) GenerateWRounds(length, rounds int) []byte {
+ if length > s.SaltLenMax {
+ length = s.SaltLenMax
+ } else if length < s.SaltLenMin {
+ length = s.SaltLenMin
+ }
+ if rounds < 0 {
+ rounds = s.RoundsDefault
+ } else if rounds < s.RoundsMin {
+ rounds = s.RoundsMin
+ } else if rounds > s.RoundsMax {
+ rounds = s.RoundsMax
+ }
+
+ saltLen := (length * 6 / 8)
+ if (length*6)%8 != 0 {
+ saltLen++
+ }
+ salt := make([]byte, saltLen)
+ rand.Read(salt)
+
+ roundsText := ""
+ if rounds != s.RoundsDefault {
+ roundsText = "rounds=" + strconv.Itoa(rounds) + "$"
+ }
+
+ out := make([]byte, len(s.MagicPrefix)+len(roundsText)+length)
+ copy(out, s.MagicPrefix)
+ copy(out[len(s.MagicPrefix):], []byte(roundsText))
+ copy(out[len(s.MagicPrefix)+len(roundsText):], Base64_24Bit(salt))
+ return out
+}
diff --git a/vendor/github.com/tredoe/osutil/user/crypt/crypt.go b/vendor/github.com/tredoe/osutil/user/crypt/crypt.go
new file mode 100644
index 00000000..5ded2da8
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/user/crypt/crypt.go
@@ -0,0 +1,108 @@
+// Copyright 2013, Jonas mg
+// All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+// Package crypt provides interface for password crypt functions and collects
+// common constants.
+package crypt
+
+import (
+ "errors"
+ "strings"
+
+ "github.com/tredoe/osutil/user/crypt/common"
+)
+
+var ErrKeyMismatch = errors.New("hashed value is not the hash of the given password")
+
+// Crypter is the common interface implemented by all crypt functions.
+type Crypter interface {
+ // Generate performs the hashing algorithm, returning a full hash suitable
+ // for storage and later password verification.
+ //
+ // If the salt is empty, a randomly-generated salt will be generated with a
+ // length of SaltLenMax and number RoundsDefault of rounds.
+ //
+ // Any error only can be got when the salt argument is not empty.
+ Generate(key, salt []byte) (string, error)
+
+ // Verify compares a hashed key with its possible key equivalent.
+ // Returns nil on success, or an error on failure; if the hashed key is
+ // diffrent, the error is "ErrKeyMismatch".
+ Verify(hashedKey string, key []byte) error
+
+ // Cost returns the hashing cost (in rounds) used to create the given hashed
+ // key.
+ //
+ // When, in the future, the hashing cost of a key needs to be increased in
+ // order to adjust for greater computational power, this function allows one
+ // to establish which keys need to be updated.
+ //
+ // The algorithms based in MD5-crypt use a fixed value of rounds.
+ Cost(hashedKey string) (int, error)
+
+ // SetSalt sets a different salt. It is used to easily create derivated
+ // algorithms, i.e. "apr1_crypt" from "md5_crypt".
+ SetSalt(salt common.Salt)
+}
+
+// Crypt identifies a crypt function that is implemented in another package.
+type Crypt uint
+
+const (
+ APR1 Crypt = iota + 1 // import "github.com/tredoe/osutil/user/crypt/apr1_crypt"
+ MD5 // import "github.com/tredoe/osutil/user/crypt/md5_crypt"
+ SHA256 // import "github.com/tredoe/osutil/user/crypt/sha256_crypt"
+ SHA512 // import "github.com/tredoe/osutil/user/crypt/sha512_crypt"
+ maxCrypt
+)
+
+var cryptPrefixes = make([]string, maxCrypt)
+
+var crypts = make([]func() Crypter, maxCrypt)
+
+// RegisterCrypt registers a function that returns a new instance of the given
+// crypt function. This is intended to be called from the init function in
+// packages that implement crypt functions.
+func RegisterCrypt(c Crypt, f func() Crypter, prefix string) {
+ if c >= maxCrypt {
+ panic("crypt: RegisterHash of unknown crypt function")
+ }
+ crypts[c] = f
+ cryptPrefixes[c] = prefix
+}
+
+// New returns a new crypter.
+func New(c Crypt) Crypter {
+ f := crypts[c]
+ if f != nil {
+ return f()
+ }
+ panic("crypt: requested crypt function is unavailable")
+}
+
+// NewFromHash returns a new Crypter using the prefix in the given hashed key.
+func NewFromHash(hashedKey string) Crypter {
+ var f func() Crypter
+
+ if strings.HasPrefix(hashedKey, cryptPrefixes[SHA512]) {
+ f = crypts[SHA512]
+ } else if strings.HasPrefix(hashedKey, cryptPrefixes[SHA256]) {
+ f = crypts[SHA256]
+ } else if strings.HasPrefix(hashedKey, cryptPrefixes[MD5]) {
+ f = crypts[MD5]
+ } else if strings.HasPrefix(hashedKey, cryptPrefixes[APR1]) {
+ f = crypts[APR1]
+ } else {
+ toks := strings.SplitN(hashedKey, "$", 3)
+ prefix := "$" + toks[1] + "$"
+ panic("crypt: unknown cryp function from prefix: " + prefix)
+ }
+
+ if f != nil {
+ return f()
+ }
+ panic("crypt: requested cryp function is unavailable")
+}
diff --git a/vendor/github.com/tredoe/osutil/user/crypt/md5_crypt/md5_crypt.go b/vendor/github.com/tredoe/osutil/user/crypt/md5_crypt/md5_crypt.go
new file mode 100644
index 00000000..33091c8c
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/user/crypt/md5_crypt/md5_crypt.go
@@ -0,0 +1,166 @@
+// Copyright 2012, Jeramey Crawford
+// Copyright 2013, Jonas mg
+// All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+// Package md5_crypt implements the standard Unix MD5-crypt algorithm created by
+// Poul-Henning Kamp for FreeBSD.
+package md5_crypt
+
+import (
+ "bytes"
+ "crypto/md5"
+
+ "github.com/tredoe/osutil/user/crypt"
+ "github.com/tredoe/osutil/user/crypt/common"
+)
+
+func init() {
+ crypt.RegisterCrypt(crypt.MD5, New, MagicPrefix)
+}
+
+// NOTE: Cisco IOS only allows salts of length 4.
+
+const (
+ MagicPrefix = "$1$"
+ SaltLenMin = 1 // Real minimum is 0, but that isn't useful.
+ SaltLenMax = 8
+ RoundsDefault = 1000
+)
+
+type crypter struct{ Salt common.Salt }
+
+// New returns a new crypt.Crypter computing the MD5-crypt password hashing.
+func New() crypt.Crypter {
+ return &crypter{GetSalt()}
+}
+
+func (c *crypter) Generate(key, salt []byte) (string, error) {
+ if len(salt) == 0 {
+ salt = c.Salt.Generate(SaltLenMax)
+ }
+ if !bytes.HasPrefix(salt, c.Salt.MagicPrefix) {
+ return "", common.ErrSaltPrefix
+ }
+
+ saltToks := bytes.Split(salt, []byte{'$'})
+
+ if len(saltToks) < 3 {
+ return "", common.ErrSaltFormat
+ } else {
+ salt = saltToks[2]
+ }
+ if len(salt) > 8 {
+ salt = salt[0:8]
+ }
+
+ // Compute alternate MD5 sum with input KEY, SALT, and KEY.
+ Alternate := md5.New()
+ Alternate.Write(key)
+ Alternate.Write(salt)
+ Alternate.Write(key)
+ AlternateSum := Alternate.Sum(nil) // 16 bytes
+
+ A := md5.New()
+ A.Write(key)
+ A.Write(c.Salt.MagicPrefix)
+ A.Write(salt)
+ // Add for any character in the key one byte of the alternate sum.
+ i := len(key)
+ for ; i > 16; i -= 16 {
+ A.Write(AlternateSum)
+ }
+ A.Write(AlternateSum[0:i])
+
+ // The original implementation now does something weird:
+ // For every 1 bit in the key, the first 0 is added to the buffer
+ // For every 0 bit, the first character of the key
+ // This does not seem to be what was intended but we have to follow this to
+ // be compatible.
+ for i = len(key); i > 0; i >>= 1 {
+ if (i & 1) == 0 {
+ A.Write(key[0:1])
+ } else {
+ A.Write([]byte{0})
+ }
+ }
+ Csum := A.Sum(nil)
+
+ // In fear of password crackers here comes a quite long loop which just
+ // processes the output of the previous round again.
+ // We cannot ignore this here.
+ for i = 0; i < RoundsDefault; i++ {
+ C := md5.New()
+
+ // Add key or last result.
+ if (i & 1) != 0 {
+ C.Write(key)
+ } else {
+ C.Write(Csum)
+ }
+ // Add salt for numbers not divisible by 3.
+ if (i % 3) != 0 {
+ C.Write(salt)
+ }
+ // Add key for numbers not divisible by 7.
+ if (i % 7) != 0 {
+ C.Write(key)
+ }
+ // Add key or last result.
+ if (i & 1) == 0 {
+ C.Write(key)
+ } else {
+ C.Write(Csum)
+ }
+
+ Csum = C.Sum(nil)
+ }
+
+ out := make([]byte, 0, 23+len(c.Salt.MagicPrefix)+len(salt))
+ out = append(out, c.Salt.MagicPrefix...)
+ out = append(out, salt...)
+ out = append(out, '$')
+ out = append(out, common.Base64_24Bit([]byte{
+ Csum[12], Csum[6], Csum[0],
+ Csum[13], Csum[7], Csum[1],
+ Csum[14], Csum[8], Csum[2],
+ Csum[15], Csum[9], Csum[3],
+ Csum[5], Csum[10], Csum[4],
+ Csum[11],
+ })...)
+
+ // Clean sensitive data.
+ A.Reset()
+ Alternate.Reset()
+ for i = 0; i < len(AlternateSum); i++ {
+ AlternateSum[i] = 0
+ }
+
+ return string(out), nil
+}
+
+func (c *crypter) Verify(hashedKey string, key []byte) error {
+ newHash, err := c.Generate(key, []byte(hashedKey))
+ if err != nil {
+ return err
+ }
+ if newHash != hashedKey {
+ return crypt.ErrKeyMismatch
+ }
+ return nil
+}
+
+func (c *crypter) Cost(hashedKey string) (int, error) { return RoundsDefault, nil }
+
+func (c *crypter) SetSalt(salt common.Salt) { c.Salt = salt }
+
+func GetSalt() common.Salt {
+ return common.Salt{
+ MagicPrefix: []byte(MagicPrefix),
+ SaltLenMin: SaltLenMin,
+ SaltLenMax: SaltLenMax,
+ RoundsDefault: RoundsDefault,
+ }
+}
diff --git a/vendor/github.com/tredoe/osutil/user/crypt/sha256_crypt/sha256_crypt.go b/vendor/github.com/tredoe/osutil/user/crypt/sha256_crypt/sha256_crypt.go
new file mode 100644
index 00000000..fe30746d
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/user/crypt/sha256_crypt/sha256_crypt.go
@@ -0,0 +1,243 @@
+// Copyright 2012, Jeramey Crawford
+// Copyright 2013, Jonas mg
+// All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+// Package sha256_crypt implements Ulrich Drepper's SHA256-crypt password
+// hashing algorithm.
+//
+// The specification for this algorithm can be found here:
+// http://www.akkadia.org/drepper/SHA-crypt.txt
+package sha256_crypt
+
+import (
+ "bytes"
+ "crypto/sha256"
+ "strconv"
+
+ "github.com/tredoe/osutil/user/crypt"
+ "github.com/tredoe/osutil/user/crypt/common"
+)
+
+func init() {
+ crypt.RegisterCrypt(crypt.SHA256, New, MagicPrefix)
+}
+
+const (
+ MagicPrefix = "$5$"
+ SaltLenMin = 1
+ SaltLenMax = 16
+ RoundsMin = 1000
+ RoundsMax = 999999999
+ RoundsDefault = 5000
+)
+
+var _rounds = []byte("rounds=")
+
+type crypter struct{ Salt common.Salt }
+
+// New returns a new crypt.Crypter computing the SHA256-crypt password hashing.
+func New() crypt.Crypter {
+ return &crypter{GetSalt()}
+}
+
+func (c *crypter) Generate(key, salt []byte) (string, error) {
+ var rounds int
+ var isRoundsDef bool
+
+ if len(salt) == 0 {
+ salt = c.Salt.GenerateWRounds(SaltLenMax, RoundsDefault)
+ }
+ if !bytes.HasPrefix(salt, c.Salt.MagicPrefix) {
+ return "", common.ErrSaltPrefix
+ }
+
+ saltToks := bytes.Split(salt, []byte{'$'})
+ if len(saltToks) < 3 {
+ return "", common.ErrSaltFormat
+ }
+
+ if bytes.HasPrefix(saltToks[2], _rounds) {
+ isRoundsDef = true
+ pr, err := strconv.ParseInt(string(saltToks[2][7:]), 10, 32)
+ if err != nil {
+ return "", common.ErrSaltRounds
+ }
+ rounds = int(pr)
+ if rounds < RoundsMin {
+ rounds = RoundsMin
+ } else if rounds > RoundsMax {
+ rounds = RoundsMax
+ }
+ salt = saltToks[3]
+ } else {
+ rounds = RoundsDefault
+ salt = saltToks[2]
+ }
+
+ if len(salt) > 16 {
+ salt = salt[0:16]
+ }
+
+ // Compute alternate SHA256 sum with input KEY, SALT, and KEY.
+ Alternate := sha256.New()
+ Alternate.Write(key)
+ Alternate.Write(salt)
+ Alternate.Write(key)
+ AlternateSum := Alternate.Sum(nil) // 32 bytes
+
+ A := sha256.New()
+ A.Write(key)
+ A.Write(salt)
+ // Add for any character in the key one byte of the alternate sum.
+ i := len(key)
+ for ; i > 32; i -= 32 {
+ A.Write(AlternateSum)
+ }
+ A.Write(AlternateSum[0:i])
+
+ // Take the binary representation of the length of the key and for every add
+ // the alternate sum, for every 0 the key.
+ for i = len(key); i > 0; i >>= 1 {
+ if (i & 1) != 0 {
+ A.Write(AlternateSum)
+ } else {
+ A.Write(key)
+ }
+ }
+ Asum := A.Sum(nil)
+
+ // Start computation of P byte sequence.
+ P := sha256.New()
+ // For every character in the password add the entire password.
+ for i = 0; i < len(key); i++ {
+ P.Write(key)
+ }
+ Psum := P.Sum(nil)
+ // Create byte sequence P.
+ Pseq := make([]byte, 0, len(key))
+ for i = len(key); i > 32; i -= 32 {
+ Pseq = append(Pseq, Psum...)
+ }
+ Pseq = append(Pseq, Psum[0:i]...)
+
+ // Start computation of S byte sequence.
+ S := sha256.New()
+ for i = 0; i < (16 + int(Asum[0])); i++ {
+ S.Write(salt)
+ }
+ Ssum := S.Sum(nil)
+ // Create byte sequence S.
+ Sseq := make([]byte, 0, len(salt))
+ for i = len(salt); i > 32; i -= 32 {
+ Sseq = append(Sseq, Ssum...)
+ }
+ Sseq = append(Sseq, Ssum[0:i]...)
+
+ Csum := Asum
+
+ // Repeatedly run the collected hash value through SHA256 to burn CPU cycles.
+ for i = 0; i < rounds; i++ {
+ C := sha256.New()
+
+ // Add key or last result.
+ if (i & 1) != 0 {
+ C.Write(Pseq)
+ } else {
+ C.Write(Csum)
+ }
+ // Add salt for numbers not divisible by 3.
+ if (i % 3) != 0 {
+ C.Write(Sseq)
+ }
+ // Add key for numbers not divisible by 7.
+ if (i % 7) != 0 {
+ C.Write(Pseq)
+ }
+ // Add key or last result.
+ if (i & 1) != 0 {
+ C.Write(Csum)
+ } else {
+ C.Write(Pseq)
+ }
+
+ Csum = C.Sum(nil)
+ }
+
+ out := make([]byte, 0, 80)
+ out = append(out, c.Salt.MagicPrefix...)
+ if isRoundsDef {
+ out = append(out, []byte("rounds="+strconv.Itoa(rounds)+"$")...)
+ }
+ out = append(out, salt...)
+ out = append(out, '$')
+ out = append(out, common.Base64_24Bit([]byte{
+ Csum[20], Csum[10], Csum[0],
+ Csum[11], Csum[1], Csum[21],
+ Csum[2], Csum[22], Csum[12],
+ Csum[23], Csum[13], Csum[3],
+ Csum[14], Csum[4], Csum[24],
+ Csum[5], Csum[25], Csum[15],
+ Csum[26], Csum[16], Csum[6],
+ Csum[17], Csum[7], Csum[27],
+ Csum[8], Csum[28], Csum[18],
+ Csum[29], Csum[19], Csum[9],
+ Csum[30], Csum[31],
+ })...)
+
+ // Clean sensitive data.
+ A.Reset()
+ Alternate.Reset()
+ P.Reset()
+ for i = 0; i < len(Asum); i++ {
+ Asum[i] = 0
+ }
+ for i = 0; i < len(AlternateSum); i++ {
+ AlternateSum[i] = 0
+ }
+ for i = 0; i < len(Pseq); i++ {
+ Pseq[i] = 0
+ }
+
+ return string(out), nil
+}
+
+func (c *crypter) Verify(hashedKey string, key []byte) error {
+ newHash, err := c.Generate(key, []byte(hashedKey))
+ if err != nil {
+ return err
+ }
+ if newHash != hashedKey {
+ return crypt.ErrKeyMismatch
+ }
+ return nil
+}
+
+func (c *crypter) Cost(hashedKey string) (int, error) {
+ saltToks := bytes.Split([]byte(hashedKey), []byte{'$'})
+ if len(saltToks) < 3 {
+ return 0, common.ErrSaltFormat
+ }
+
+ if !bytes.HasPrefix(saltToks[2], _rounds) {
+ return RoundsDefault, nil
+ }
+ roundToks := bytes.Split(saltToks[2], []byte{'='})
+ cost, err := strconv.ParseInt(string(roundToks[1]), 10, 0)
+ return int(cost), err
+}
+
+func (c *crypter) SetSalt(salt common.Salt) { c.Salt = salt }
+
+func GetSalt() common.Salt {
+ return common.Salt{
+ MagicPrefix: []byte(MagicPrefix),
+ SaltLenMin: SaltLenMin,
+ SaltLenMax: SaltLenMax,
+ RoundsDefault: RoundsDefault,
+ RoundsMin: RoundsMin,
+ RoundsMax: RoundsMax,
+ }
+}
diff --git a/vendor/github.com/tredoe/osutil/user/crypt/sha512_crypt/sha512_crypt.go b/vendor/github.com/tredoe/osutil/user/crypt/sha512_crypt/sha512_crypt.go
new file mode 100644
index 00000000..fd55e881
--- /dev/null
+++ b/vendor/github.com/tredoe/osutil/user/crypt/sha512_crypt/sha512_crypt.go
@@ -0,0 +1,254 @@
+// Copyright 2012, Jeramey Crawford
+// Copyright 2013, Jonas mg
+// All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+// Package sha512_crypt implements Ulrich Drepper's SHA512-crypt password
+// hashing algorithm.
+//
+// The specification for this algorithm can be found here:
+// http://www.akkadia.org/drepper/SHA-crypt.txt
+package sha512_crypt
+
+import (
+ "bytes"
+ "crypto/sha512"
+ "strconv"
+
+ "github.com/tredoe/osutil/user/crypt"
+ "github.com/tredoe/osutil/user/crypt/common"
+)
+
+func init() {
+ crypt.RegisterCrypt(crypt.SHA512, New, MagicPrefix)
+}
+
+const (
+ MagicPrefix = "$6$"
+ SaltLenMin = 1
+ SaltLenMax = 16
+ RoundsMin = 1000
+ RoundsMax = 999999999
+ RoundsDefault = 5000
+)
+
+var _rounds = []byte("rounds=")
+
+type crypter struct{ Salt common.Salt }
+
+// New returns a new crypt.Crypter computing the SHA512-crypt password hashing.
+func New() crypt.Crypter {
+ return &crypter{GetSalt()}
+}
+
+func (c *crypter) Generate(key, salt []byte) (string, error) {
+ var rounds int
+ var isRoundsDef bool
+
+ if len(salt) == 0 {
+ salt = c.Salt.GenerateWRounds(SaltLenMax, RoundsDefault)
+ }
+ if !bytes.HasPrefix(salt, c.Salt.MagicPrefix) {
+ return "", common.ErrSaltPrefix
+ }
+
+ saltToks := bytes.Split(salt, []byte{'$'})
+ if len(saltToks) < 3 {
+ return "", common.ErrSaltFormat
+ }
+
+ if bytes.HasPrefix(saltToks[2], _rounds) {
+ isRoundsDef = true
+ pr, err := strconv.ParseInt(string(saltToks[2][7:]), 10, 32)
+ if err != nil {
+ return "", common.ErrSaltRounds
+ }
+ rounds = int(pr)
+ if rounds < RoundsMin {
+ rounds = RoundsMin
+ } else if rounds > RoundsMax {
+ rounds = RoundsMax
+ }
+ salt = saltToks[3]
+ } else {
+ rounds = RoundsDefault
+ salt = saltToks[2]
+ }
+
+ if len(salt) > SaltLenMax {
+ salt = salt[0:SaltLenMax]
+ }
+
+ // Compute alternate SHA512 sum with input KEY, SALT, and KEY.
+ Alternate := sha512.New()
+ Alternate.Write(key)
+ Alternate.Write(salt)
+ Alternate.Write(key)
+ AlternateSum := Alternate.Sum(nil) // 64 bytes
+
+ A := sha512.New()
+ A.Write(key)
+ A.Write(salt)
+ // Add for any character in the key one byte of the alternate sum.
+ i := len(key)
+ for ; i > 64; i -= 64 {
+ A.Write(AlternateSum)
+ }
+ A.Write(AlternateSum[0:i])
+
+ // Take the binary representation of the length of the key and for every add
+ // the alternate sum, for every 0 the key.
+ for i = len(key); i > 0; i >>= 1 {
+ if (i & 1) != 0 {
+ A.Write(AlternateSum)
+ } else {
+ A.Write(key)
+ }
+ }
+ Asum := A.Sum(nil)
+
+ // Start computation of P byte sequence.
+ P := sha512.New()
+ // For every character in the password add the entire password.
+ for i = 0; i < len(key); i++ {
+ P.Write(key)
+ }
+ Psum := P.Sum(nil)
+ // Create byte sequence P.
+ Pseq := make([]byte, 0, len(key))
+ for i = len(key); i > 64; i -= 64 {
+ Pseq = append(Pseq, Psum...)
+ }
+ Pseq = append(Pseq, Psum[0:i]...)
+
+ // Start computation of S byte sequence.
+ S := sha512.New()
+ for i = 0; i < (16 + int(Asum[0])); i++ {
+ S.Write(salt)
+ }
+ Ssum := S.Sum(nil)
+ // Create byte sequence S.
+ Sseq := make([]byte, 0, len(salt))
+ for i = len(salt); i > 64; i -= 64 {
+ Sseq = append(Sseq, Ssum...)
+ }
+ Sseq = append(Sseq, Ssum[0:i]...)
+
+ Csum := Asum
+
+ // Repeatedly run the collected hash value through SHA512 to burn CPU cycles.
+ for i = 0; i < rounds; i++ {
+ C := sha512.New()
+
+ // Add key or last result.
+ if (i & 1) != 0 {
+ C.Write(Pseq)
+ } else {
+ C.Write(Csum)
+ }
+ // Add salt for numbers not divisible by 3.
+ if (i % 3) != 0 {
+ C.Write(Sseq)
+ }
+ // Add key for numbers not divisible by 7.
+ if (i % 7) != 0 {
+ C.Write(Pseq)
+ }
+ // Add key or last result.
+ if (i & 1) != 0 {
+ C.Write(Csum)
+ } else {
+ C.Write(Pseq)
+ }
+
+ Csum = C.Sum(nil)
+ }
+
+ out := make([]byte, 0, 123)
+ out = append(out, c.Salt.MagicPrefix...)
+ if isRoundsDef {
+ out = append(out, []byte("rounds="+strconv.Itoa(rounds)+"$")...)
+ }
+ out = append(out, salt...)
+ out = append(out, '$')
+ out = append(out, common.Base64_24Bit([]byte{
+ Csum[42], Csum[21], Csum[0],
+ Csum[1], Csum[43], Csum[22],
+ Csum[23], Csum[2], Csum[44],
+ Csum[45], Csum[24], Csum[3],
+ Csum[4], Csum[46], Csum[25],
+ Csum[26], Csum[5], Csum[47],
+ Csum[48], Csum[27], Csum[6],
+ Csum[7], Csum[49], Csum[28],
+ Csum[29], Csum[8], Csum[50],
+ Csum[51], Csum[30], Csum[9],
+ Csum[10], Csum[52], Csum[31],
+ Csum[32], Csum[11], Csum[53],
+ Csum[54], Csum[33], Csum[12],
+ Csum[13], Csum[55], Csum[34],
+ Csum[35], Csum[14], Csum[56],
+ Csum[57], Csum[36], Csum[15],
+ Csum[16], Csum[58], Csum[37],
+ Csum[38], Csum[17], Csum[59],
+ Csum[60], Csum[39], Csum[18],
+ Csum[19], Csum[61], Csum[40],
+ Csum[41], Csum[20], Csum[62],
+ Csum[63],
+ })...)
+
+ // Clean sensitive data.
+ A.Reset()
+ Alternate.Reset()
+ P.Reset()
+ for i = 0; i < len(Asum); i++ {
+ Asum[i] = 0
+ }
+ for i = 0; i < len(AlternateSum); i++ {
+ AlternateSum[i] = 0
+ }
+ for i = 0; i < len(Pseq); i++ {
+ Pseq[i] = 0
+ }
+
+ return string(out), nil
+}
+
+func (c *crypter) Verify(hashedKey string, key []byte) error {
+ newHash, err := c.Generate(key, []byte(hashedKey))
+ if err != nil {
+ return err
+ }
+ if newHash != hashedKey {
+ return crypt.ErrKeyMismatch
+ }
+ return nil
+}
+
+func (c *crypter) Cost(hashedKey string) (int, error) {
+ saltToks := bytes.Split([]byte(hashedKey), []byte{'$'})
+ if len(saltToks) < 3 {
+ return 0, common.ErrSaltFormat
+ }
+
+ if !bytes.HasPrefix(saltToks[2], _rounds) {
+ return RoundsDefault, nil
+ }
+ roundToks := bytes.Split(saltToks[2], []byte{'='})
+ cost, err := strconv.ParseInt(string(roundToks[1]), 10, 0)
+ return int(cost), err
+}
+
+func (c *crypter) SetSalt(salt common.Salt) { c.Salt = salt }
+
+func GetSalt() common.Salt {
+ return common.Salt{
+ MagicPrefix: []byte(MagicPrefix),
+ SaltLenMin: SaltLenMin,
+ SaltLenMax: SaltLenMax,
+ RoundsDefault: RoundsDefault,
+ RoundsMin: RoundsMin,
+ RoundsMax: RoundsMax,
+ }
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index cf48ea8a..acc73e4c 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1,8 +1,5 @@
# cloud.google.com/go v0.38.0
cloud.google.com/go/compute/metadata
-# github.com/abbot/go-http-auth v0.4.1-0.20220112235402-e1cee1c72f2f
-## explicit
-github.com/abbot/go-http-auth
# github.com/aws/aws-sdk-go v1.40.41
## explicit
github.com/aws/aws-sdk-go/aws
@@ -189,6 +186,14 @@ github.com/tidwall/pretty
# github.com/tidwall/sjson v1.0.4
## explicit
github.com/tidwall/sjson
+# github.com/tredoe/osutil v1.0.6
+## explicit
+github.com/tredoe/osutil/user/crypt
+github.com/tredoe/osutil/user/crypt/apr1_crypt
+github.com/tredoe/osutil/user/crypt/common
+github.com/tredoe/osutil/user/crypt/md5_crypt
+github.com/tredoe/osutil/user/crypt/sha256_crypt
+github.com/tredoe/osutil/user/crypt/sha512_crypt
# github.com/wayneashleyberry/terminal-dimensions v1.1.0
## explicit
github.com/wayneashleyberry/terminal-dimensions