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:
VeillaxandClaude Sonnet 5.5 committed 2026-10-26 02:41:44 -06:00
1 parent c7c2ae8f8d
commit 2259580adf
16 files changed
+1359 -1

No files matched your search

+58
View File
@@ -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
}