Last active
August 31, 2016 15:22
-
-
Save SamWhited/0ceab67b05668e6c6dcf8c05aab1243c to your computer and use it in GitHub Desktop.
Jitsi Meet mod_token_auth ASAP test server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
testtoken | |
main | |
*.sw[op] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The testtoken command creates a new ASAP token for a Jitsi Meet instance, | |
// signs it, and serves the public key which can be used to verify that | |
// signature in such a way that Jitsi Meet's mod_token_auth Prosody plugin can | |
// find it. | |
package main | |
import ( | |
"crypto/rand" | |
"crypto/rsa" | |
"crypto/sha256" | |
"crypto/x509" | |
"encoding/base64" | |
"encoding/hex" | |
"encoding/pem" | |
"errors" | |
"flag" | |
"fmt" | |
"log" | |
"net/http" | |
"net/url" | |
"path" | |
"time" | |
"golang.org/x/oauth2/jws" | |
) | |
// Number of random bytes generated for random room names. | |
const randLen = 8 | |
func main() { | |
var appid, listen, root, room, kid, dur string | |
flag.StringVar(&root, "url", "https://sam.jitsi.net", "The root URL to create a token for.") | |
flag.StringVar(&room, "room", "", "The room name for the token (random if empty).") | |
flag.StringVar(&kid, "kid", "/myapp/mykey.pem", "The key ID (path on the keyserver) for an ASAP public key.") | |
flag.StringVar(&dur, "dur", "1h", "The duration of the token.") | |
flag.StringVar(&listen, "listen", ":8080", "The address to listen on.") | |
flag.StringVar(&appid, "iss", "lonely", "The issuer (application ID) of the token.") | |
flag.Parse() | |
var err error | |
if room == "" { | |
if room, err = genRoomName(); err != nil { | |
log.Fatal("Error while generating room name:", err) | |
} | |
} | |
rootURL, err := url.Parse(root) | |
if err != nil { | |
log.Fatalf(`Error while parsing URL "%s": %v`, root, err) | |
} | |
// Get values for the time claims (expiration and issued at) | |
now := time.Now() | |
duration, err := time.ParseDuration(dur) | |
if err != nil { | |
log.Fatal("Error while parsing token duration:", err) | |
} | |
exp := now.Unix() + int64(duration.Seconds()) | |
// Generate a private key to use | |
privkey, err := rsa.GenerateKey(cryptoRand{}, 2048) | |
if err != nil { | |
log.Fatal("Error generating private key:", err) | |
} | |
x509pubkey, err := x509.MarshalPKIXPublicKey(privkey.Public()) | |
if err != nil { | |
log.Fatal("Error saving RSA public key:", err) | |
} | |
header := &jws.Header{ | |
Algorithm: "RS256", | |
Typ: "JWT", | |
KeyID: kid, | |
} | |
claims := &jws.ClaimSet{ | |
Exp: exp, | |
Iss: appid, | |
Iat: now.Unix(), | |
PrivateClaims: map[string]interface{}{ | |
"room": room, | |
}, | |
} | |
token, err := jws.Encode(header, claims, privkey) | |
if err != nil { | |
log.Fatalf("Error while encoding token:", err) | |
} | |
rootURL.Path = path.Join(rootURL.Path, room) | |
rootURL.RawQuery = "jwt=" + token | |
fmt.Println(rootURL.String()) | |
pubBlock := &pem.Block{ | |
Type: "PUBLIC KEY", | |
Bytes: x509pubkey, | |
} | |
h := sha256.New() | |
if _, err = h.Write([]byte(kid)); err != nil { | |
log.Fatalf("Error while processing file path:", err) | |
} | |
pathBytes := h.Sum(nil) | |
p := hex.EncodeToString(pathBytes) + ".pem" | |
http.HandleFunc(p, func(w http.ResponseWriter, r *http.Request) { | |
time.Sleep(30 * time.Second) | |
if err := pem.Encode(w, pubBlock); err != nil { | |
log.Println("Error while saving key to output stream:", err) | |
} | |
}) | |
fmt.Printf("Serving public key at %s…\n", path.Join(listen, p)) | |
log.Fatal(http.ListenAndServe(listen, nil)) | |
} | |
// Generate a random room name. | |
func genRoomName() (string, error) { | |
b := make([]byte, randLen) | |
n, err := rand.Read(b) | |
switch { | |
case err != nil: | |
return "", err | |
case n != randLen: | |
return "", errors.New("Failed to read enough randomness") | |
} | |
return base64.RawURLEncoding.EncodeToString(b), nil | |
} | |
type cryptoRand struct{} | |
func (cryptoRand) Read(p []byte) (int, error) { | |
return rand.Read(p) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment