2020-05-30 23:14:40 +00:00
|
|
|
package authstore
|
|
|
|
|
|
|
|
import (
|
2020-06-01 07:38:18 +00:00
|
|
|
"crypto/rand"
|
2020-05-31 12:19:41 +00:00
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/base64"
|
|
|
|
"errors"
|
2020-07-18 05:28:12 +00:00
|
|
|
"fmt"
|
2020-07-20 15:27:31 +00:00
|
|
|
"os"
|
2020-05-30 23:14:40 +00:00
|
|
|
"time"
|
2020-06-01 07:38:18 +00:00
|
|
|
|
2020-07-20 22:20:59 +00:00
|
|
|
"git.rootprojects.org/root/telebit/dbg"
|
2020-06-01 07:38:18 +00:00
|
|
|
jwt "github.com/dgrijalva/jwt-go"
|
2020-05-30 23:14:40 +00:00
|
|
|
)
|
|
|
|
|
2020-05-31 12:19:41 +00:00
|
|
|
var ErrExists = errors.New("token already exists")
|
2020-08-14 09:24:32 +00:00
|
|
|
var ErrNotFound = errors.New("record not found")
|
2020-05-31 12:19:41 +00:00
|
|
|
|
2020-05-30 23:14:40 +00:00
|
|
|
type Authorization struct {
|
|
|
|
ID string `db:"id,omitempty" json:"-"`
|
|
|
|
|
|
|
|
MachinePPID string `db:"machine_ppid,omitempty" json:"machine_ppid,omitempty"`
|
|
|
|
PublicKey string `db:"public_key,omitempty" json:"public_key,omitempty"`
|
|
|
|
SharedKey string `db:"shared_key,omitempty" json:"shared_key"`
|
|
|
|
Slug string `db:"slug,omitempty" json:"slug"`
|
|
|
|
|
|
|
|
CreatedAt time.Time `db:"created_at,omitempty" json:"created_at,omitempty"`
|
|
|
|
UpdatedAt time.Time `db:"updated_at,omitempty" json:"updated_at,omitempty"`
|
|
|
|
DeletedAt time.Time `db:"deleted_at,omitempty" json:"-"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Store interface {
|
2020-05-30 23:45:36 +00:00
|
|
|
SetMaster(secret string) error
|
2020-05-30 23:14:40 +00:00
|
|
|
Add(auth *Authorization) error
|
|
|
|
Set(auth *Authorization) error
|
2020-06-01 08:39:35 +00:00
|
|
|
Active() ([]Authorization, error)
|
2020-06-01 08:48:05 +00:00
|
|
|
Inactive() ([]Authorization, error)
|
2020-05-31 12:19:41 +00:00
|
|
|
Touch(id string) error
|
2020-05-30 23:14:40 +00:00
|
|
|
Get(id string) (*Authorization, error)
|
|
|
|
GetBySlug(id string) (*Authorization, error)
|
|
|
|
GetByPub(id string) (*Authorization, error)
|
|
|
|
Delete(auth *Authorization) error
|
|
|
|
Close() error
|
|
|
|
}
|
2020-05-31 12:19:41 +00:00
|
|
|
|
|
|
|
func ToPublicKeyString(secret string) string {
|
|
|
|
pubBytes := sha256.Sum256([]byte(secret))
|
|
|
|
pub := base64.RawURLEncoding.EncodeToString(pubBytes[:])
|
|
|
|
if len(pub) > 24 {
|
|
|
|
pub = pub[:24]
|
|
|
|
}
|
|
|
|
return pub
|
|
|
|
}
|
2020-06-01 07:38:18 +00:00
|
|
|
|
2020-11-12 13:30:52 +00:00
|
|
|
func HMACToken(secret string, leeway time.Duration, maybeExp ...int) (token string, err error) {
|
2020-06-01 07:38:18 +00:00
|
|
|
keyID := ToPublicKeyString(secret)
|
2020-07-18 05:28:12 +00:00
|
|
|
if dbg.Debug {
|
2020-07-20 15:27:31 +00:00
|
|
|
fmt.Fprintf(os.Stderr, "[debug] keyID=%s\n", keyID)
|
2020-07-18 05:28:12 +00:00
|
|
|
}
|
2020-06-01 07:38:18 +00:00
|
|
|
|
2020-07-20 18:18:08 +00:00
|
|
|
var exp int64
|
|
|
|
if 0 == len(maybeExp) || 0 == maybeExp[0] {
|
|
|
|
exp = time.Now().Add(5 * time.Minute).Unix()
|
|
|
|
} else {
|
|
|
|
exp = time.Now().Add(time.Duration(maybeExp[0]) * time.Second).Unix()
|
|
|
|
}
|
|
|
|
|
2020-06-01 07:38:18 +00:00
|
|
|
b := make([]byte, 16)
|
|
|
|
_, _ = rand.Read(b)
|
|
|
|
claims := &jwt.StandardClaims{
|
|
|
|
Id: base64.RawURLEncoding.EncodeToString(b),
|
2020-06-22 06:34:42 +00:00
|
|
|
Subject: "", // TODO
|
|
|
|
Issuer: "", // TODO
|
2020-09-03 19:47:57 +00:00
|
|
|
IssuedAt: time.Now().Add(-leeway).Unix(),
|
|
|
|
ExpiresAt: exp + int64(leeway.Seconds()),
|
2020-06-01 07:38:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
jwtToken := &jwt.Token{
|
|
|
|
Header: map[string]interface{}{
|
|
|
|
"kid": keyID,
|
|
|
|
"typ": "JWT",
|
|
|
|
"alg": jwt.SigningMethodHS256.Alg(),
|
|
|
|
},
|
|
|
|
Claims: claims,
|
|
|
|
Method: jwt.SigningMethodHS256,
|
|
|
|
}
|
|
|
|
|
|
|
|
if token, err = jwtToken.SignedString([]byte(secret)); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return token, nil
|
|
|
|
}
|