Add the shared packages for the sharks stack
model, tunnel, wg, authtoken, netguard, docker and dotenv, split out of the original single repository so Hammerhead, Blacktip and Bamboo can live in their own repos and import them. README extended; LICENSE unchanged. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c7c2ae8f8d
commit
2259580adf
16 files changed
+1359
-1
No files matched your search
@@ -0,0 +1,58 @@
|
||||
// Package authtoken signs the short tokens hammerhead hands to visitors and blacktip verifies.
|
||||
package authtoken
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
KindCallback = "cb" // minted by hammerhead after a successful login, valid for minutes
|
||||
KindSession = "sess" // minted by blacktip for the visitor's cookie
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
Mapping string `json:"m"`
|
||||
Sub string `json:"sub"` // who: an email, "password", "pin", "share:name"
|
||||
Kind string `json:"k"`
|
||||
Exp int64 `json:"exp"`
|
||||
// Epoch is the resource's login generation when this was issued. Hammerhead
|
||||
// bumps it to sign every visitor out (a member removed, a password changed);
|
||||
// tokens from an older epoch are then refused without any per-token state.
|
||||
Epoch int64 `json:"ep"`
|
||||
}
|
||||
|
||||
var enc = base64.RawURLEncoding
|
||||
|
||||
func mac(key, payload string) string {
|
||||
m := hmac.New(sha256.New, []byte(key))
|
||||
m.Write([]byte(payload))
|
||||
return enc.EncodeToString(m.Sum(nil))
|
||||
}
|
||||
|
||||
func Sign(key string, t Token) string {
|
||||
b, _ := json.Marshal(t)
|
||||
p := enc.EncodeToString(b)
|
||||
return p + "." + mac(key, p)
|
||||
}
|
||||
|
||||
// Verify checks the signature, kind, mapping, epoch and expiry.
|
||||
func Verify(key, tok, kind, mapping string, epoch int64) (Token, bool) {
|
||||
var t Token
|
||||
p, sig, found := strings.Cut(tok, ".")
|
||||
if !found || !hmac.Equal([]byte(sig), []byte(mac(key, p))) {
|
||||
return t, false
|
||||
}
|
||||
b, err := enc.DecodeString(p)
|
||||
if err != nil || json.Unmarshal(b, &t) != nil {
|
||||
return t, false
|
||||
}
|
||||
if t.Kind != kind || t.Mapping != mapping || t.Epoch != epoch || time.Now().Unix() > t.Exp {
|
||||
return t, false
|
||||
}
|
||||
return t, true
|
||||
}
|
||||
Reference in new issue
Block a user