telebit/cmd/signjwt/signjwt.go

184 lines
4.4 KiB
Go
Raw Normal View History

2020-05-26 09:05:39 +00:00
package main
import (
"crypto/hmac"
"crypto/sha256"
2020-05-31 12:19:41 +00:00
"encoding/base64"
"encoding/hex"
2020-07-06 09:23:12 +00:00
"flag"
2020-05-26 09:05:39 +00:00
"fmt"
"os"
2020-07-20 18:18:08 +00:00
"strconv"
2020-11-12 13:30:52 +00:00
"time"
2020-05-26 09:05:39 +00:00
2020-11-13 11:26:25 +00:00
"git.rootprojects.org/root/telebit"
2020-07-22 08:09:06 +00:00
"git.rootprojects.org/root/telebit/dbg"
2020-11-13 11:26:25 +00:00
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
2020-05-31 12:19:41 +00:00
"github.com/denisbrodbeck/machineid"
2020-05-26 09:05:39 +00:00
_ "github.com/joho/godotenv/autoload"
)
2020-07-20 18:18:08 +00:00
var durAbbrs = map[byte]bool{
's': true, // second
'm': true, // minute
'h': true, // hour
'd': true, // day
'w': true, // week
// month and year cannot be measured
}
2020-05-26 09:05:39 +00:00
func main() {
2020-07-19 08:16:11 +00:00
var secret, clientSecret, relaySecret string
2020-11-12 13:30:52 +00:00
debug := flag.Bool("debug", true, "show more debug output")
machinePPID := flag.String("machine-ppid", "", "spoof the machine ppid")
machineID := flag.String("machine-id", "", "spoof the raw machine id")
vendorID := flag.String("vendor-id", "", "a unique identifier for a deploy target environment")
2020-07-06 09:23:12 +00:00
authURL := flag.String("auth-url", "", "the base url for authentication, if not the same as the tunnel relay")
2020-07-20 18:18:08 +00:00
humanExp := flag.String("expires-in", "15m", "set the token to expire <x> units after `iat` (issued at)")
getMachinePPID := flag.Bool("machine-ppid-only", false, "just print the machine ppid, not the token")
2020-07-19 08:16:11 +00:00
flag.StringVar(&secret, "secret", "", "either the remote server or the tunnel relay secret (used for JWT authentication)")
2020-07-06 09:23:12 +00:00
flag.Parse()
2020-05-26 09:05:39 +00:00
2020-11-12 13:30:52 +00:00
if *debug {
dbg.Debug = *debug
}
2020-07-19 08:16:11 +00:00
if 0 == len(*authURL) {
*authURL = os.Getenv("AUTH_URL")
}
2020-07-20 18:18:08 +00:00
humanExpLen := len(*humanExp)
if 0 == humanExpLen {
fmt.Fprintf(os.Stderr, "Invalid --expires-in: %q (minimum: 5s)", *humanExp)
}
expNum, _ := strconv.Atoi((*humanExp)[:humanExpLen-1])
expSuffix := (*humanExp)[humanExpLen-1:]
switch expSuffix {
case "w":
expNum *= 7
fallthrough
case "d":
expNum *= 24
fallthrough
case "h":
expNum *= 60
fallthrough
case "m":
expNum *= 60
fallthrough
case "s":
// do nothing
default:
fmt.Fprintf(os.Stderr, "Invalid --expires-in: %q (minimum: 5s)", *humanExp)
}
if expNum < 5 {
fmt.Fprintf(os.Stderr, "Invalid --expires-in: %q (minimum: 5s)", *humanExp)
}
if 0 == len(*vendorID) {
*vendorID = os.Getenv("VENDOR_ID")
2020-05-26 09:05:39 +00:00
}
if 0 == len(*vendorID) {
*vendorID = "telebit.io"
2020-07-06 09:23:12 +00:00
}
2020-07-19 08:16:11 +00:00
if 0 == len(secret) {
clientSecret = os.Getenv("CLIENT_SECRET")
relaySecret = os.Getenv("RELAY_SECRET")
if 0 == len(relaySecret) {
relaySecret = os.Getenv("SECRET")
2020-07-06 09:23:12 +00:00
}
}
2020-07-19 08:16:11 +00:00
if 0 == len(secret) {
secret = clientSecret
2020-07-06 09:23:12 +00:00
}
2020-07-19 08:16:11 +00:00
if 0 == len(secret) {
secret = relaySecret
2020-07-06 09:23:12 +00:00
}
2020-07-19 08:16:11 +00:00
if 0 == len(secret) && 0 == len(clientSecret) && 0 == len(relaySecret) {
fmt.Fprintf(os.Stderr, "See usage: signjwt --help\n")
os.Exit(1)
return
} else if 0 != len(clientSecret) && 0 != len(relaySecret) {
fmt.Fprintf(os.Stderr, "Use only one of $SECRET or --relay-secret or --client-secret\n")
2020-05-26 09:05:39 +00:00
os.Exit(1)
return
}
ppid := *machinePPID
if 0 == len(ppid) {
appID := fmt.Sprintf("%s|%s", *vendorID, secret)
var muid string
var err error
if 0 == len(*machineID) {
muid, err = machineid.ProtectedID(appID)
if nil != err {
fmt.Fprintf(os.Stderr, "unauthorized device: %s\n", err)
os.Exit(1)
return
}
} else {
muid = ProtectMachineID(appID, *machineID)
}
muidBytes, _ := hex.DecodeString(muid)
ppid = base64.RawURLEncoding.EncodeToString(muidBytes)
2020-07-06 09:23:12 +00:00
}
2020-07-22 08:09:06 +00:00
if dbg.Debug {
fmt.Fprintf(os.Stderr, "[debug] vendorID = %s\n", *vendorID)
fmt.Fprintf(os.Stderr, "[debug] secret = %s\n", secret)
}
2020-07-19 08:16:11 +00:00
pub := authstore.ToPublicKeyString(ppid)
if *getMachinePPID {
2020-07-22 08:09:06 +00:00
if dbg.Debug {
fmt.Fprintf(os.Stderr, "[debug]: <ppid> <pub>\n")
}
2020-07-19 08:16:11 +00:00
fmt.Fprintf(
os.Stdout,
"%s %s\n",
ppid,
pub,
)
return
2020-05-31 12:19:41 +00:00
}
2020-07-22 08:09:06 +00:00
if dbg.Debug {
fmt.Fprintf(os.Stderr, "[debug] ppid = %s\n", ppid)
fmt.Fprintf(os.Stderr, "[debug] pub = %s\n", pub)
}
2020-07-19 08:16:11 +00:00
2020-11-12 13:30:52 +00:00
tok, err := authstore.HMACToken(ppid, 15*time.Minute, expNum)
2020-05-26 09:05:39 +00:00
if nil != err {
2020-07-06 09:23:12 +00:00
fmt.Fprintf(os.Stderr, "signing error: %s\n", err)
2020-05-26 09:05:39 +00:00
os.Exit(1)
return
}
2020-07-22 08:09:06 +00:00
if dbg.Debug {
fmt.Fprintf(os.Stderr, "[debug] <token>\n")
}
fmt.Printf("%s\n", tok)
2020-07-06 09:23:12 +00:00
2020-07-19 08:16:11 +00:00
if "" != *authURL {
grants, err := telebit.Inspect(*authURL, tok)
if nil != err {
fmt.Fprintf(os.Stderr, "inspect relay token failed:\n%s\n", err)
os.Exit(1)
}
2020-07-22 08:09:06 +00:00
if dbg.Debug {
fmt.Fprintf(os.Stderr, "[debug] <grants>\n")
fmt.Fprintf(os.Stderr, "%+v\n", grants)
}
2020-07-06 09:23:12 +00:00
}
2020-05-26 09:05:39 +00:00
}
func ProtectMachineID(appID, machineID string) string {
mac := hmac.New(sha256.New, []byte(machineID))
mac.Write([]byte(appID))
return hex.EncodeToString(mac.Sum(nil))
}