mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-06 08:22:24 +01:00
improve (plg_authenticate_htpasswd): support additional algorithm
This commit is contained in:
parent
3b5bc80565
commit
10daf893cd
33 changed files with 1572 additions and 1231 deletions
2
go.mod
2
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
|
||||
|
|
|
|||
8
go.sum
8
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=
|
||||
|
|
|
|||
|
|
@ -56,7 +56,10 @@ func (this Admin) EntryPoint(idpParams map[string]string, req *http.Request, res
|
|||
</label>
|
||||
<button>CONNECT</button>
|
||||
` + getFlash() + `
|
||||
<style>.flash{ color: #f26d6d; font-weight: bold; }</style>
|
||||
<style>
|
||||
.flash{ color: #f26d6d; font-weight: bold; }
|
||||
form { padding-top: 10vh; }
|
||||
</style>
|
||||
</form>`)))
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
@ -25,9 +32,16 @@ func (this Htpasswd) Setup() Form {
|
|||
{
|
||||
Name: "users",
|
||||
Type: "long_text",
|
||||
Placeholder: "test:$apr1$nEDlyMK/$4jL0BUAuEifz2VajdjVnE.\ntest:{SHA}qUqP5cyxm6YcTAhz05Hph5gvu9M=",
|
||||
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 the htpasswd file format.
|
||||
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,
|
|||
</label>
|
||||
<button>CONNECT</button>
|
||||
` + getFlash() + `
|
||||
<style>.flash{ color: #f26d6d; font-weight: bold; }</style>
|
||||
<style>
|
||||
.flash{ color: #f26d6d; font-weight: bold; }
|
||||
form { padding-top: 10vh; }
|
||||
</style>
|
||||
</form>`)))
|
||||
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
|
||||
}
|
||||
|
|
|
|||
5
vendor/github.com/abbot/go-http-auth/.gitignore
generated
vendored
5
vendor/github.com/abbot/go-http-auth/.gitignore
generated
vendored
|
|
@ -1,5 +0,0 @@
|
|||
*~
|
||||
*.a
|
||||
*.6
|
||||
*.out
|
||||
_testmain.go
|
||||
178
vendor/github.com/abbot/go-http-auth/LICENSE
generated
vendored
178
vendor/github.com/abbot/go-http-auth/LICENSE
generated
vendored
|
|
@ -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
|
||||
|
||||
12
vendor/github.com/abbot/go-http-auth/Makefile
generated
vendored
12
vendor/github.com/abbot/go-http-auth/Makefile
generated
vendored
|
|
@ -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
|
||||
71
vendor/github.com/abbot/go-http-auth/README.md
generated
vendored
71
vendor/github.com/abbot/go-http-auth/README.md
generated
vendored
|
|
@ -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, "<html><body><h1>Hello, %s!</h1></body></html>", 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.
|
||||
110
vendor/github.com/abbot/go-http-auth/auth.go
generated
vendored
110
vendor/github.com/abbot/go-http-auth/auth.go
generated
vendored
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
161
vendor/github.com/abbot/go-http-auth/basic.go
generated
vendored
161
vendor/github.com/abbot/go-http-auth/basic.go
generated
vendored
|
|
@ -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}
|
||||
}
|
||||
288
vendor/github.com/abbot/go-http-auth/digest.go
generated
vendored
288
vendor/github.com/abbot/go-http-auth/digest.go
generated
vendored
|
|
@ -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
|
||||
}
|
||||
5
vendor/github.com/abbot/go-http-auth/go.mod
generated
vendored
5
vendor/github.com/abbot/go-http-auth/go.mod
generated
vendored
|
|
@ -1,5 +0,0 @@
|
|||
module github.com/abbot/go-http-auth
|
||||
|
||||
go 1.14
|
||||
|
||||
require golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||
8
vendor/github.com/abbot/go-http-auth/go.sum
generated
vendored
8
vendor/github.com/abbot/go-http-auth/go.sum
generated
vendored
|
|
@ -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=
|
||||
73
vendor/github.com/abbot/go-http-auth/md5crypt.go
generated
vendored
73
vendor/github.com/abbot/go-http-auth/md5crypt.go
generated
vendored
|
|
@ -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...)
|
||||
}
|
||||
146
vendor/github.com/abbot/go-http-auth/misc.go
generated
vendored
146
vendor/github.com/abbot/go-http-auth/misc.go
generated
vendored
|
|
@ -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"
|
||||
1
vendor/github.com/abbot/go-http-auth/test.htdigest
generated
vendored
1
vendor/github.com/abbot/go-http-auth/test.htdigest
generated
vendored
|
|
@ -1 +0,0 @@
|
|||
test:example.com:aa78524fceb0e50fd8ca96dd818b8cf9
|
||||
4
vendor/github.com/abbot/go-http-auth/test.htpasswd
generated
vendored
4
vendor/github.com/abbot/go-http-auth/test.htpasswd
generated
vendored
|
|
@ -1,4 +0,0 @@
|
|||
test:{SHA}qvTGHdzF6KLavt4PO0gs2a6pQ00=
|
||||
test2:$apr1$a0j62R97$mYqFkloXH0/UOaUnAiV2b0
|
||||
test16:$apr1$JI4wh3am$AmhephVqLTUyAVpFQeHZC0
|
||||
test3:$2y$05$ih3C91zUBSTFcAh2mQnZYuob0UOZVEf16wl/ukgjDhjvj.xgM1WwS
|
||||
151
vendor/github.com/abbot/go-http-auth/users.go
generated
vendored
151
vendor/github.com/abbot/go-http-auth/users.go
generated
vendored
|
|
@ -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
|
||||
}
|
||||
}
|
||||
16
vendor/github.com/tredoe/osutil/AUTHORS.md
generated
vendored
Normal file
16
vendor/github.com/tredoe/osutil/AUTHORS.md
generated
vendored
Normal file
|
|
@ -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 <email address> / (url address)
|
||||
|
||||
(The email address is not required for organizations)
|
||||
|
||||
Please keep the list sorted.
|
||||
|
||||
## Code
|
||||
|
||||
* Jonas mg (https://github.com/tredoe)
|
||||
22
vendor/github.com/tredoe/osutil/CONTRIBUTORS.md
generated
vendored
Normal file
22
vendor/github.com/tredoe/osutil/CONTRIBUTORS.md
generated
vendored
Normal file
|
|
@ -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 <email address> / (url address)
|
||||
|
||||
Please keep the list sorted.
|
||||
|
||||
## Code
|
||||
|
||||
* Jonas mg (https://github.com/tredoe)
|
||||
|
||||
* DJ Gregor <dj@gregor.com>
|
||||
* Jeramey Crawford <jeramey@antihe.ro>
|
||||
* Misha Seltzer (https://github.com/mishas)
|
||||
374
vendor/github.com/tredoe/osutil/LICENSE-MPL.txt
generated
vendored
Normal file
374
vendor/github.com/tredoe/osutil/LICENSE-MPL.txt
generated
vendored
Normal file
|
|
@ -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.
|
||||
|
||||
8
vendor/github.com/tredoe/osutil/user/crypt/AUTHORS.md
generated
vendored
Normal file
8
vendor/github.com/tredoe/osutil/user/crypt/AUTHORS.md
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
### Initial author
|
||||
|
||||
[Jeramey Crawford](https://github.com/jeramey)
|
||||
|
||||
### Other authors
|
||||
|
||||
[Jonas mg](https://github.com/tredoe)
|
||||
|
||||
27
vendor/github.com/tredoe/osutil/user/crypt/LICENSE
generated
vendored
Normal file
27
vendor/github.com/tredoe/osutil/user/crypt/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2012, Jeramey Crawford <jeramey@antihe.ro>
|
||||
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.
|
||||
25
vendor/github.com/tredoe/osutil/user/crypt/README.md
generated
vendored
Normal file
25
vendor/github.com/tredoe/osutil/user/crypt/README.md
generated
vendored
Normal file
|
|
@ -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 <https://github.com/jeramey/go-pwhash>
|
||||
|
||||
## 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.
|
||||
62
vendor/github.com/tredoe/osutil/user/crypt/apr1_crypt/apr1_crypt.go
generated
vendored
Normal file
62
vendor/github.com/tredoe/osutil/user/crypt/apr1_crypt/apr1_crypt.go
generated
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
60
vendor/github.com/tredoe/osutil/user/crypt/common/base64.go
generated
vendored
Normal file
60
vendor/github.com/tredoe/osutil/user/crypt/common/base64.go
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
|
||||
// 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
|
||||
}
|
||||
13
vendor/github.com/tredoe/osutil/user/crypt/common/doc.go
generated
vendored
Normal file
13
vendor/github.com/tredoe/osutil/user/crypt/common/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
|
||||
// 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
|
||||
105
vendor/github.com/tredoe/osutil/user/crypt/common/salt.go
generated
vendored
Normal file
105
vendor/github.com/tredoe/osutil/user/crypt/common/salt.go
generated
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
|
||||
// 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
|
||||
}
|
||||
108
vendor/github.com/tredoe/osutil/user/crypt/crypt.go
generated
vendored
Normal file
108
vendor/github.com/tredoe/osutil/user/crypt/crypt.go
generated
vendored
Normal file
|
|
@ -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")
|
||||
}
|
||||
166
vendor/github.com/tredoe/osutil/user/crypt/md5_crypt/md5_crypt.go
generated
vendored
Normal file
166
vendor/github.com/tredoe/osutil/user/crypt/md5_crypt/md5_crypt.go
generated
vendored
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
243
vendor/github.com/tredoe/osutil/user/crypt/sha256_crypt/sha256_crypt.go
generated
vendored
Normal file
243
vendor/github.com/tredoe/osutil/user/crypt/sha256_crypt/sha256_crypt.go
generated
vendored
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
254
vendor/github.com/tredoe/osutil/user/crypt/sha512_crypt/sha512_crypt.go
generated
vendored
Normal file
254
vendor/github.com/tredoe/osutil/user/crypt/sha512_crypt/sha512_crypt.go
generated
vendored
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
11
vendor/modules.txt
vendored
11
vendor/modules.txt
vendored
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue