finish implementing registration invites
This commit is contained in:
parent
b7888158b8
commit
e7caa27a35
5 changed files with 117 additions and 14 deletions
|
@ -13,7 +13,7 @@ func ProcessCmd(args []string, userStore auth.UserStore, crypto register.Symmetr
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
switch args[1] {
|
switch args[1] {
|
||||||
case "register":
|
case "invite":
|
||||||
now := time.Now().UnixMicro()
|
now := time.Now().UnixMicro()
|
||||||
strNow := strconv.FormatInt(now, 10)
|
strNow := strconv.FormatInt(now, 10)
|
||||||
self, err := crypto.Encrypt(strNow)
|
self, err := crypto.Encrypt(strNow)
|
||||||
|
|
|
@ -1,31 +1,50 @@
|
||||||
package register
|
package register
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
"strconv"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
|
||||||
"hacklab.nilfm.cc/quartzgun/auth"
|
"hacklab.nilfm.cc/quartzgun/auth"
|
||||||
"hacklab.nilfm.cc/quartzgun/renderer"
|
"hacklab.nilfm.cc/quartzgun/renderer"
|
||||||
"hacklab.nilfm.cc/quartzgun/router"
|
"hacklab.nilfm.cc/quartzgun/router"
|
||||||
|
"hacklab.nilfm.cc/quartzgun/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var bytes = []byte{99, 207, 33, 57, 28, 01, 50, 76, 01, 92, 33, 10, 48, 07, 00, 250}
|
|
||||||
|
|
||||||
type SymmetricCrypto interface {
|
type SymmetricCrypto interface {
|
||||||
Encode(b []byte) string
|
Encode(b []byte) string
|
||||||
Decode(s string) []byte
|
Decode(s string) []byte
|
||||||
Encrypt(text string) (string, error)
|
Encrypt(text string) (string, error)
|
||||||
Decrypt(text string) (string, error)
|
Decrypt(text string) (string, error)
|
||||||
|
IsValid(text string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type SymmetricCrypt struct {
|
type SymmetricCrypt struct {
|
||||||
Secret string
|
Secret string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var iv []byte = []byte {107, 53, 46, 249, 52, 70, 36, 185,
|
||||||
|
168, 139, 144, 249, 242, 2, 125, 183 }
|
||||||
|
|
||||||
|
func (self *SymmetricCrypt) IsValid(cipher string) bool {
|
||||||
|
stringTimestamp, err := self.Decrypt(cipher)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
int64Timestamp, err := strconv.ParseInt(stringTimestamp, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
then := time.UnixMicro(int64Timestamp)
|
||||||
|
return time.Since(then).Minutes() <= 15
|
||||||
|
}
|
||||||
|
|
||||||
func (self *SymmetricCrypt) Encode(b []byte) string {
|
func (self *SymmetricCrypt) Encode(b []byte) string {
|
||||||
return hex.EncodeToString(b)
|
return hex.EncodeToString(b)
|
||||||
}
|
}
|
||||||
|
@ -39,12 +58,13 @@ func (self *SymmetricCrypt) Decode(s string) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SymmetricCrypt) Encrypt(text string) (string, error) {
|
func (self *SymmetricCrypt) Encrypt(text string) (string, error) {
|
||||||
|
fmt.Println(text)
|
||||||
block, err := aes.NewCipher([]byte(self.Secret))
|
block, err := aes.NewCipher([]byte(self.Secret))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
plainText := []byte(text)
|
plainText := []byte(text)
|
||||||
cfb := cipher.NewCFBEncrypter(block, bytes)
|
cfb := cipher.NewCFBEncrypter(block, iv)
|
||||||
cipherText := make([]byte, len(plainText))
|
cipherText := make([]byte, len(plainText))
|
||||||
cfb.XORKeyStream(cipherText, plainText)
|
cfb.XORKeyStream(cipherText, plainText)
|
||||||
return self.Encode(cipherText), nil
|
return self.Encode(cipherText), nil
|
||||||
|
@ -56,7 +76,7 @@ func (self *SymmetricCrypt) Decrypt(text string) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
cipherText := self.Decode(text)
|
cipherText := self.Decode(text)
|
||||||
cfb := cipher.NewCFBDecrypter(block, bytes)
|
cfb := cipher.NewCFBDecrypter(block, iv)
|
||||||
plainText := make([]byte, len(cipherText))
|
plainText := make([]byte, len(cipherText))
|
||||||
cfb.XORKeyStream(plainText, cipherText)
|
cfb.XORKeyStream(plainText, cipherText)
|
||||||
return string(plainText), nil
|
return string(plainText), nil
|
||||||
|
@ -64,18 +84,24 @@ func (self *SymmetricCrypt) Decrypt(text string) (string, error) {
|
||||||
|
|
||||||
func WithCrypto(next http.Handler, crypto SymmetricCrypto) http.Handler {
|
func WithCrypto(next http.Handler, crypto SymmetricCrypto) http.Handler {
|
||||||
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
||||||
//urlParams := req.Context().Value("params").(map[string]string)
|
util.AddContextValue(req, "crypto", crypto);
|
||||||
//cipher := urlParams["cipher"]
|
|
||||||
|
|
||||||
next.ServeHTTP(w, req)
|
next.ServeHTTP(w, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(handlerFunc)
|
return http.HandlerFunc(handlerFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithUserStore(next http.Handler, udb auth.UserStore) http.Handler {
|
func WithUserStoreAndCrypto(next http.Handler, udb auth.UserStore, crypto SymmetricCrypto) http.Handler {
|
||||||
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
||||||
*req = *req.WithContext(context.WithValue(req.Context(), "udb", udb))
|
urlParams := req.Context().Value("params").(map[string]string)
|
||||||
|
success := false
|
||||||
|
cipher := urlParams["cipher"]
|
||||||
|
username := req.FormValue("username")
|
||||||
|
password := req.FormValue("password")
|
||||||
|
if crypto.IsValid(cipher) && len(username) > 0 && len(password) > 0 {
|
||||||
|
success = udb.AddUser(username, password) == nil
|
||||||
|
}
|
||||||
|
util.AddContextValue(req, "success", success);
|
||||||
next.ServeHTTP(w, req)
|
next.ServeHTTP(w, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,8 +112,8 @@ func CreateRegistrationInterface(udb auth.UserStore, secret string) http.Handler
|
||||||
rtr := &router.Router{Fallback: *template.Must(template.ParseFiles("templates/error.html"))}
|
rtr := &router.Router{Fallback: *template.Must(template.ParseFiles("templates/error.html"))}
|
||||||
crypto := &SymmetricCrypt{Secret: secret}
|
crypto := &SymmetricCrypt{Secret: secret}
|
||||||
|
|
||||||
rtr.Get(`/(?P<cipher>.*)`, WithCrypto(renderer.Template("templates/register.html"), crypto))
|
rtr.Get(`/(?P<cipher>\S+)`, WithCrypto(renderer.Template("templates/register.html"), crypto))
|
||||||
rtr.Post(`/(?P<cipher>.*)`, WithUserStore(WithCrypto(renderer.Template("templates/registered.html"), crypto), udb))
|
rtr.Post(`/(?P<cipher>\S+)`, WithUserStoreAndCrypto(renderer.Template("templates/registered.html"), udb, crypto))
|
||||||
|
|
||||||
return http.HandlerFunc(rtr.ServeHTTP)
|
return http.HandlerFunc(rtr.ServeHTTP)
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,7 +142,7 @@ pre {
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui_win a {
|
.ui_win a {
|
||||||
color: #1f9b92;
|
color: var(--main_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui_win a:hover, ui_win a:active {
|
.ui_win a:hover, ui_win a:active {
|
||||||
|
@ -197,4 +197,35 @@ nav {
|
||||||
.two_btn_list li {
|
.two_btn_list li {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr auto auto;
|
grid-template-columns: 1fr auto auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#registration {
|
||||||
|
background: var(--bg_color);
|
||||||
|
color: var(--fg_color);
|
||||||
|
width: 500px;
|
||||||
|
max-width: 80vw;
|
||||||
|
margin: 2em auto;
|
||||||
|
text-align: center;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#registration h1, #registration form {
|
||||||
|
margin: 1em auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#registration label, #registration button {
|
||||||
|
display: block;
|
||||||
|
margin: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#registration button {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#registration a {
|
||||||
|
color: var(--main_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#registration a:hover {
|
||||||
|
color: var(--fg_color);
|
||||||
}
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
{{ $cipher := ((.Context).Value "params").cipher }}
|
||||||
|
{{ $valid := ((.Context).Value "crypto").IsValid $cipher }}
|
||||||
|
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Felt — Admin Registration</title>
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<link href="/table/style.css" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main id="registration">
|
||||||
|
<h1>Felt Admin Registration</h1>
|
||||||
|
{{ if $valid }}
|
||||||
|
<form action="/register/{{ $cipher }}" method="post">
|
||||||
|
<label>username <input id="username" name="username"/></label>
|
||||||
|
<label>password <input id="password" name="password" type="password"/></label>
|
||||||
|
<button type="submit">Register</button>
|
||||||
|
</form>
|
||||||
|
{{ else }}
|
||||||
|
<p class="error">The registration token you provided is invalid</p>
|
||||||
|
{{end}}
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
{{ $success := ((.Context).Value "success") }}
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Felt — Registration Complete</title>
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<link href="/table/style.css" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main id="registration">
|
||||||
|
{{ if $success }}
|
||||||
|
<h1>Registration Complete</h1>
|
||||||
|
<p>Success! <a href="/table">Let's game!</a></p>
|
||||||
|
{{ else }}
|
||||||
|
<h1>Error</h1>
|
||||||
|
<p class="error">Something went wrong; please try a different username or obtain a new registration code.</p>
|
||||||
|
{{end}}
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue