-
Notifications
You must be signed in to change notification settings - Fork 0
/
digest.go
72 lines (58 loc) · 1.65 KB
/
digest.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package glinet
import (
"crypto/md5"
"encoding/hex"
"fmt"
"github.com/GehirnInc/crypt/md5_crypt"
)
type DigestService service
type challengeRequest struct {
Username string `json:"username"`
}
type challengeResponse struct {
Salt string `json:"salt"`
Algorithm int `json:"alg"`
Nonce string `json:"nonce"`
}
type loginRequest struct {
Username string `json:"username"`
Hash string `json:"hash"`
}
type loginResponse struct {
Username string `json:"username"`
Sid string `json:"sid"`
}
func (s *DigestService) Challenge(username string) (*challengeResponse, error) {
requestBody := challengeRequest{Username: username}
var responseBody challengeResponse
err := s.client.CallWithInterface("challenge", &requestBody, &responseBody)
if err != nil {
return nil, err
}
return &responseBody, nil
}
func (s *DigestService) Login(username string, password []byte) (*loginResponse, error) {
challenge, err := s.Challenge(username)
if err != nil {
return nil, err
}
md5PasswordHash, err := md5_crypt.New().Generate(password, []byte(fmt.Sprintf("$1$%s", challenge.Salt)))
if err != nil {
return nil, err
}
// call challenge again because it sometimes times out
challenge, err = s.Challenge(username)
if err != nil {
return nil, err
}
loginHash := md5.Sum([]byte(fmt.Sprintf("%s:%s:%s", username, md5PasswordHash, challenge.Nonce)))
digest := make([]byte, hex.EncodedLen(len(loginHash)))
hex.Encode(digest, loginHash[:])
request := loginRequest{Username: username, Hash: string(digest)}
var res loginResponse
err = s.client.CallWithInterface("login", &request, &res)
if err != nil {
return nil, err
}
return &res, nil
}