amuse.git

commit ae729d1891c4ce8449dffd98685f666914caaa93

Author: Adam <git@apiote.tk>

keep data after error in signup

 front/capnproto.go | 2 
 front/html.go | 11 ++++----
 front/renderer.go | 4 +-
 go.mod | 2 
 go.sum | 4 +-
 libamuse/qr.go | 10 --------
 libamuse/signup.go | 56 ++++++++++++++++++++++++++++++++++++++++----
 router.go | 25 +++----------------
 templates/signup.html | 6 ++--


diff --git a/front/capnproto.go b/front/capnproto.go
index 47c382070fcbdc931c3ea86075a68b04991f401a..415ecbf730ac465a0c72e7c14d82a450eb7bc80e 100644
--- a/front/capnproto.go
+++ b/front/capnproto.go
@@ -56,7 +56,7 @@ 	// todo throw Wrong Accept
 	return TODO("implement CapnprotoRenderer.RenderLogin").(string)
 }
 
-func (CapnprotoRenderer) RenderSignup(languages []language.Tag, err error, otp *otp.Key) string {
+func (CapnprotoRenderer) RenderSignup(languages []language.Tag, err error, otp *otp.Key, sfaEnabled bool, username, qr string) string {
 	// todo throw Wrong Accept
 	return TODO("implement CapnprotoRenderer.RenderSignup").(string)
 }




diff --git a/front/html.go b/front/html.go
index 5e3d6c17cad45814ae196a54e226f06d9552049e..4b7cf47308ddc67eacd01e9929435272c3bd04a5 100644
--- a/front/html.go
+++ b/front/html.go
@@ -11,7 +11,6 @@
 	"bytes"
 	"golang.org/x/text/language"
 	"html/template"
-	"net/url"
 	"strings"
 	"time"
 
@@ -141,11 +140,13 @@ 	data.State.Error = authError
 	return render(languages, data, "login")
 }
 
-func (HtmlRenderer) RenderSignup(languages []language.Tag, authError error, key *otp.Key) string {
+func (HtmlRenderer) RenderSignup(languages []language.Tag, authError error, key *otp.Key, sfaEnabled bool, username, qr string) string {
 	secret := struct {
-		Secret string
-		Url    string
-	}{key.Secret(), url.QueryEscape(key.URL())}
+		Secret     string
+		SfaEnabled bool
+		Username   string
+		Qr         template.URL
+	}{key.Secret(), sfaEnabled, username, template.URL(qr)}
 	data := RenderData{Data: secret}
 	data.State.Error = authError
 	return render(languages, data, "signup")




diff --git a/front/renderer.go b/front/renderer.go
index 9c97247f40f1ba5dddd13923cd4da31c7f9a90d3..92917be7e499e9a6b7326f3ad6063c76b8377491 100644
--- a/front/renderer.go
+++ b/front/renderer.go
@@ -2,9 +2,9 @@ package front
 
 import (
 	"notabug.org/apiote/amuse/accounts"
+	"notabug.org/apiote/amuse/datastructure"
 	"notabug.org/apiote/amuse/tmdb"
 	"notabug.org/apiote/amuse/wikidata"
-	"notabug.org/apiote/amuse/datastructure"
 
 	"golang.org/x/text/language"
 
@@ -30,7 +30,7 @@ 	RenderBookSerie(wikidata.BookSerie, []language.Tag) string
 	RenderAbout([]language.Tag) string
 	RenderErrorPage(int, []language.Tag) string
 	RenderLogin([]language.Tag, error, string) string
-	RenderSignup([]language.Tag, error, *otp.Key) string
+	RenderSignup([]language.Tag, error, *otp.Key, bool, string, string) string
 	RenderSignedup([]language.Tag, []string) string
 	RenderWatchlist(datastructure.Watchlist, []language.Tag) string
 	RenderTvQueue(datastructure.TvQueue, []language.Tag) string




diff --git a/go.mod b/go.mod
index bb857afb77b8b875145ee8d625f43792c7b9213d..b72aafa49b3fae1a42889bd08d3d0eded0001da6 100644
--- a/go.mod
+++ b/go.mod
@@ -6,6 +6,7 @@ require (
 	github.com/BurntSushi/toml v0.3.1
 	github.com/alecthomas/chroma v0.7.2 // indirect
 	github.com/bytesparadise/libasciidoc v0.4.0
+	github.com/chai2010/webp v1.1.0
 	github.com/dlclark/regexp2 v1.2.0 // indirect
 	github.com/go-python/gopy v0.3.1
 	github.com/knakk/digest v0.0.0-20160404164910-fd45becddc49 // indirect
@@ -18,7 +19,6 @@ 	github.com/onsi/gomega v1.7.1 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pquerna/otp v1.2.0
 	github.com/sirupsen/logrus v1.5.0 // indirect
-	github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086
 	github.com/stretchr/testify v1.4.0 // indirect
 	golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5
 	golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f // indirect




diff --git a/go.sum b/go.sum
index 46fd581a60d78651ea4deabeb756cf39e266a46b..4011a704db57a6ac454fdb8116494b3507666825 100644
--- a/go.sum
+++ b/go.sum
@@ -14,6 +14,8 @@ github.com/bytesparadise/libasciidoc v0.2.0 h1:W+Yh4cXehuQvFA+Ncs4tIgwBXiH8ie+KhHmMXkBhIcc=
 github.com/bytesparadise/libasciidoc v0.2.0/go.mod h1:CZX8GIEkxy/LHrDZjPbNrE16RQFDrnG6hBjnjXcD34Y=
 github.com/bytesparadise/libasciidoc v0.4.0 h1:fse9nKBTZ1OcAltOhf5XJUxctakbiaDT3Jw6qCPaM7Y=
 github.com/bytesparadise/libasciidoc v0.4.0/go.mod h1:fNxeS06tJufiBEyZJXnO0ng4xv8EdlswK/tKStNz/MA=
+github.com/chai2010/webp v1.1.0 h1:4Ei0/BRroMF9FaXDG2e4OxwFcuW2vcXd+A6tyqTJUQQ=
+github.com/chai2010/webp v1.1.0/go.mod h1:LP12PG5IFmLGHUU26tBiCBKnghxx3toZFwDjOYvd3Ow=
 github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
 github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -83,8 +85,6 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
 github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
-github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086 h1:RYiqpb2ii2Z6J4x0wxK46kvPBbFuZcdhS+CIztmYgZs=
-github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
 github.com/sozorogami/gover v0.0.0-20171022184752-b58185e213c5 h1:TAPeDBsd52dRWoWzf5trgBzxzMYHTYjYI+4xNyCdoCU=
 github.com/sozorogami/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:nHNlDYIQZn44RvqH0kCpl/dMMVWXkav0QIgzGxV1Ab4=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=




diff --git a/libamuse/qr.go b/libamuse/qr.go
deleted file mode 100644
index 095a87e459decbc8739d5d2ecd2e63e3bc381878..0000000000000000000000000000000000000000
--- a/libamuse/qr.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package libamuse
-
-import (
-	"github.com/skip2/go-qrcode"
-)
-
-func ShowQr(keyUrl string) (string, error){
-	png, err := qrcode.Encode(keyUrl, qrcode.Low, 256)  // todo webp
-	return string(png), err
-}




diff --git a/libamuse/signup.go b/libamuse/signup.go
index de8aa6cbdfdb0b6da9f2996068ac579e8b487dba..0d61856af34772eafecd13a6ef65fa60f56fec79 100644
--- a/libamuse/signup.go
+++ b/libamuse/signup.go
@@ -3,41 +3,85 @@
 import (
 	"notabug.org/apiote/amuse/accounts"
 
+	"bytes"
+	"encoding/base32"
+	"encoding/base64"
 	"errors"
+	"image"
 	"strings"
 
+	"github.com/chai2010/webp"
 	"github.com/pquerna/otp"
 	"github.com/pquerna/otp/totp"
 	"notabug.org/apiote/gott"
 )
 
 func createSecret(args ...interface{}) (interface{}, error) {
+	var (
+		err     error
+		secretB []byte
+	)
+
 	result := args[1].(*Result)
-	opts := totp.GenerateOpts{ // todo host
-		Issuer:      "amuse.apiote.tk",
-		AccountName: "nearly_headless_nick@amuse.apiote.tk",
+	secret := args[4].(string)
+	host := args[6].(string)
+
+	if len(secret) > 0 {
+		secretB, err = base32.StdEncoding.DecodeString(secret)
+	}
+	opts := totp.GenerateOpts{
+		Issuer:      host,
+		AccountName: "nearly_headless_nick@" + host,
+		Secret:      secretB,
 	}
 	key, err := totp.Generate(opts)
 	result.result = key
 	return gott.Tuple(args), err
 }
 
+func createImage(args ...interface{}) (interface{}, error) {
+	result := args[1].(*Result)
+	secret := result.result.(*otp.Key)
+	image, err := secret.Image(256, 256)
+	result.result2 = image
+	return gott.Tuple(args), err
+}
+
+func encodeWebp(args ...interface{}) (interface{}, error) {
+	result := args[1].(*Result)
+	image := result.result2.(image.Image)
+	var buf bytes.Buffer
+	err := webp.Encode(&buf, image, &webp.Options{Lossless: true})
+
+	data := "data:image/webp;base64,"
+	data += base64.StdEncoding.EncodeToString(buf.Bytes())
+	result.result2 = data
+
+	return gott.Tuple(args), err
+}
+
 func renderSignup(args ...interface{}) interface{} {
 	result := args[1].(*Result)
 	secret := result.result.(*otp.Key)
+	qr := result.result2.(string)
+	sfaEnabled := args[3].(bool)
+	username := args[5].(string)
+
 	var authError error
 	if args[2] != nil {
 		authError = args[2].(error)
 	}
-	result.page = result.renderer.RenderSignup(result.languages, authError, secret)
+	result.page = result.renderer.RenderSignup(result.languages, authError, secret, sfaEnabled, username, qr)
 	return gott.Tuple(args)
 }
 
-func ShowSignup(acceptLanguages, mimetype string, err error) (string, error) {
+func ShowSignup(acceptLanguages, mimetype string, err error, sfaEnabled bool, sfaSecret, username, host string) (string, error) {
 	r, err := gott.
-		NewResult(gott.Tuple{&RequestData{language: acceptLanguages, mimetype: mimetype}, &Result{}, err}).
+		NewResult(gott.Tuple{&RequestData{language: acceptLanguages, mimetype: mimetype}, &Result{}, err, sfaEnabled, sfaSecret, username, host}).
 		Bind(parseLanguage).
 		Bind(createSecret).
+		Bind(createImage).
+		Bind(encodeWebp).
 		Bind(createRenderer).
 		Map(renderSignup).
 		Finish()




diff --git a/router.go b/router.go
index 5fc3a84ea1453e367b729a9816dd01cba40ab4a9..29955d0204f2aadcb6af8e609fd151e5f61ce8b9 100644
--- a/router.go
+++ b/router.go
@@ -226,12 +226,13 @@
 func signupGet(w http.ResponseWriter, r *http.Request, acceptLanguages, mimetype string) {
 	auth := getAuthToken(r)
 	user, _ := libamuse.VerifyAuthToken(auth)
+	host := r.Host
 	if !user.IsEmpty() {
 		w.Header().Add("Location", "/")
 		w.WriteHeader(303)
 		return
 	}
-	signup, err := libamuse.ShowSignup(acceptLanguages, mimetype, nil)
+	signup, err := libamuse.ShowSignup(acceptLanguages, mimetype, nil, false, "", "", host)
 	render(signup, err, w, acceptLanguages, mimetype)
 }
 
@@ -244,6 +245,7 @@ 	passwordConfirm := r.PostForm.Get("password2")
 	sfaEnabled := r.PostForm.Get("sfaEnabled") == "true"
 	sfaSecret := r.PostForm.Get("sfaSecret")
 	sfa := r.PostForm.Get("sfa")
+	host := r.Host
 
 	recoveryCodes, err := libamuse.DoSignup(username, password, passwordConfirm, sfaEnabled, sfaSecret, sfa)
 	if err != nil {
@@ -252,7 +254,7 @@ 		if authErr, ok := err.(accounts.AuthError); ok {
 			var signup string
 			var err error
 			if mimetype == "text/html" {
-				signup, err = libamuse.ShowSignup(acceptLanguages, mimetype, &authErr)
+				signup, err = libamuse.ShowSignup(acceptLanguages, mimetype, &authErr, sfaEnabled, sfaSecret, username, host)
 			} else {
 				// todo send capnproto not authed
 			}
@@ -460,24 +462,6 @@ 		}
 	}
 }
 
-func qr(w http.ResponseWriter, r *http.Request) {
-	query := r.URL.Query().Get("url")
-	acceptLanguages := r.Header.Get("Accept-Language")
-	mimetype := strings.Split(r.Header.Get("Accept"), ",")[0]
-
-	keyUrl, err := url.QueryUnescape(query)
-	if err != nil {
-		render("", errors.New("400"), w, acceptLanguages, mimetype)
-	}
-
-	qr, err := libamuse.ShowQr(keyUrl)
-	w.Header().Set("Content-Type", "image/png; charset=utf-8")
-	if err != nil {
-		render("", err, w, acceptLanguages, mimetype)
-	}
-	w.Write([]byte(qr))
-}
-
 func route(port int) {
 	portStr := fmt.Sprintf(":%d", port)
 
@@ -495,7 +479,6 @@
 	http.HandleFunc("/login", login)
 	http.HandleFunc("/signup", signup)
 	http.HandleFunc("/signedup", signedup)
-	http.HandleFunc("/qr/", qr)
 	fmt.Printf("running on %s\n", portStr)
 	e := http.ListenAndServe(portStr, nil)
 	if e != nil {




diff --git a/templates/signup.html b/templates/signup.html
index 08e59561d9066056f7f8567272faf4afab2cb369..cf10cac54d08072a77aa5dec329658e593de89dc 100644
--- a/templates/signup.html
+++ b/templates/signup.html
@@ -25,18 +25,18 @@ 						
Error
{{ end }} <form action="/signup" method="POST" class="clear-float"> <label for="username" class="sans block font-1 margin-top-1">Username</label> - <input autofocus type="text" required id="username" name="username" class="block bg-none border-none border-bottom text font-1_5" /> + <input autofocus type="text" required id="username" name="username" value="{{.Data.Username}}" class="block bg-none border-none border-bottom text font-1_5" /> <label for="password" class="sans block font-1 margin-top-1">Pasword</label> <input type="password" required id="password" name="password" class="block bg-none border-none border-bottom text font-1_5" /> <label for="password2" class="sans block font-1 margin-top-1">Confirm password</label> <input type="password" required id="password2" name="password2" class="block bg-none border-none border-bottom text font-1_5" /> <div class="margin-tb-2 border-_5 border-grey padding-tb-_5 padding-lr-_25 border-solid"> <label for="sfa-enabled" class="sans font-1 margin-top-1">Enable second factor authentication <span title="Use Your favourite TOTP app" class="material-icon">&#xe887</span></label> - <input type="checkbox" id="sfa-enabled" class="" name="sfaEnabled" value="true"/> + <input type="checkbox" id="sfa-enabled" class="" name="sfaEnabled" value="true" {{if .Data.SfaEnabled}}checked{{end}}/> <div class="" id="sfa-box"> <input type="hidden" name="sfaSecret" class="margin-lr-_5 margin-tb-_5 text bg-none border-none" value="{{.Data.Secret}}" /> <div class="margin-tb-_5"> - <img src="/qr/?url={{.Data.Url}}" class="block margin-auto"/> + <img src="{{.Data.Qr}}" class="block margin-auto"/> </div> <span class="sans text-unimportant">{{.Data.Secret}}</span> <label for="sfa" class="sans block font-1 margin-top-1">Confirm second factor authentication</label>