1
0
mirror of https://github.com/writeas/writefreely synced 2025-02-08 13:18:46 +01:00

Merge pull request #244 from writeas/oauth-signup-tweaks

OAuth signup form tweaks

Resolves T715
This commit is contained in:
Matt Baer 2020-01-16 14:46:48 -05:00 committed by GitHub
commit b9914dd65a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 112 additions and 33 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2020 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -65,6 +65,7 @@ var reservedUsernames = map[string]bool{
"metadata": true, "metadata": true,
"new": true, "new": true,
"news": true, "news": true,
"oauth": true,
"post": true, "post": true,
"posts": true, "posts": true,
"privacy": true, "privacy": true,

View File

@ -1,3 +1,13 @@
/*
* Copyright © 2020 A Bunch Tell LLC.
*
* This file is part of WriteFreely.
*
* WriteFreely is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, included
* in the LICENSE file in this source code package.
*/
package writefreely package writefreely
import ( import (
@ -22,15 +32,15 @@ type viewOauthSignupVars struct {
AccessToken string AccessToken string
TokenUsername string TokenUsername string
TokenAlias string TokenAlias string // TODO: rename this to match the data it represents: the collection title
TokenEmail string TokenEmail string
TokenRemoteUser string TokenRemoteUser string
Provider string Provider string
ClientID string ClientID string
TokenHash string TokenHash string
Username string LoginUsername string
Alias string Alias string // TODO: rename this to match the data it represents: the collection title
Email string Email string
} }
@ -52,7 +62,7 @@ const (
type oauthSignupPageParams struct { type oauthSignupPageParams struct {
AccessToken string AccessToken string
TokenUsername string TokenUsername string
TokenAlias string TokenAlias string // TODO: rename this to match the data it represents: the collection title
TokenEmail string TokenEmail string
TokenRemoteUser string TokenRemoteUser string
ClientID string ClientID string
@ -91,14 +101,20 @@ func (h oauthHandler) viewOauthSignup(app *App, w http.ResponseWriter, r *http.R
return h.showOauthSignupPage(app, w, r, tp, err) return h.showOauthSignupPage(app, w, r, tp, err)
} }
hashedPass, err := auth.HashPass([]byte(r.FormValue(oauthParamPassword))) var err error
hashedPass := []byte{}
clearPass := r.FormValue(oauthParamPassword)
hasPass := clearPass != ""
if hasPass {
hashedPass, err = auth.HashPass([]byte(clearPass))
if err != nil { if err != nil {
return h.showOauthSignupPage(app, w, r, tp, fmt.Errorf("unable to hash password")) return h.showOauthSignupPage(app, w, r, tp, fmt.Errorf("unable to hash password"))
} }
}
newUser := &User{ newUser := &User{
Username: r.FormValue(oauthParamUsername), Username: r.FormValue(oauthParamUsername),
HashedPass: hashedPass, HashedPass: hashedPass,
HasPass: true, HasPass: hasPass,
Email: prepareUserEmail(r.FormValue(oauthParamEmail), h.EmailKey), Email: prepareUserEmail(r.FormValue(oauthParamEmail), h.EmailKey),
Created: time.Now().Truncate(time.Second).UTC(), Created: time.Now().Truncate(time.Second).UTC(),
} }
@ -131,13 +147,9 @@ func (h oauthHandler) validateOauthSignup(r *http.Request) error {
if len(username) > 100 { if len(username) > 100 {
return impart.HTTPError{Status: http.StatusBadRequest, Message: "Username is too long."} return impart.HTTPError{Status: http.StatusBadRequest, Message: "Username is too long."}
} }
alias := r.FormValue(oauthParamAlias) collTitle := r.FormValue(oauthParamAlias)
if len(alias) == 0 { if len(collTitle) == 0 {
return impart.HTTPError{Status: http.StatusBadRequest, Message: "Alias is too short."} collTitle = username
}
password := r.FormValue("password")
if len(password) == 0 {
return impart.HTTPError{Status: http.StatusBadRequest, Message: "Password is too short."}
} }
email := r.FormValue(oauthParamEmail) email := r.FormValue(oauthParamEmail)
if len(email) > 0 { if len(email) > 0 {
@ -151,7 +163,7 @@ func (h oauthHandler) validateOauthSignup(r *http.Request) error {
func (h oauthHandler) showOauthSignupPage(app *App, w http.ResponseWriter, r *http.Request, tp *oauthSignupPageParams, errMsg error) error { func (h oauthHandler) showOauthSignupPage(app *App, w http.ResponseWriter, r *http.Request, tp *oauthSignupPageParams, errMsg error) error {
username := tp.TokenUsername username := tp.TokenUsername
alias := tp.TokenAlias collTitle := tp.TokenAlias
email := tp.TokenEmail email := tp.TokenEmail
session, err := app.sessionStore.Get(r, cookieName) session, err := app.sessionStore.Get(r, cookieName)
@ -164,7 +176,7 @@ func (h oauthHandler) showOauthSignupPage(app *App, w http.ResponseWriter, r *ht
username = tmpValue username = tmpValue
} }
if tmpValue := r.FormValue(oauthParamAlias); len(tmpValue) > 0 { if tmpValue := r.FormValue(oauthParamAlias); len(tmpValue) > 0 {
alias = tmpValue collTitle = tmpValue
} }
if tmpValue := r.FormValue(oauthParamEmail); len(tmpValue) > 0 { if tmpValue := r.FormValue(oauthParamEmail); len(tmpValue) > 0 {
email = tmpValue email = tmpValue
@ -184,8 +196,8 @@ func (h oauthHandler) showOauthSignupPage(app *App, w http.ResponseWriter, r *ht
ClientID: tp.ClientID, ClientID: tp.ClientID,
TokenHash: tp.TokenHash, TokenHash: tp.TokenHash,
Username: username, LoginUsername: username,
Alias: alias, Alias: collTitle,
Email: email, Email: email,
} }

View File

@ -1,3 +1,13 @@
/*
* Copyright © 2019-2020 A Bunch Tell LLC.
*
* This file is part of WriteFreely.
*
* WriteFreely is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, included
* in the LICENSE file in this source code package.
*/
package writefreely package writefreely
import ( import (
@ -157,7 +167,7 @@ func (c slackOauthClient) inspectOauthAccessToken(ctx context.Context, accessTok
func (resp slackUserIdentityResponse) InspectResponse() *InspectResponse { func (resp slackUserIdentityResponse) InspectResponse() *InspectResponse {
return &InspectResponse{ return &InspectResponse{
UserID: resp.User.ID, UserID: resp.User.ID,
Username: fmt.Sprintf("%s-%s", slug.Make(resp.User.Name), store.Generate62RandomString(5)), Username: fmt.Sprintf("%s-%s", slug.Make(resp.User.Name), store.GenerateRandomString("0123456789bcdfghjklmnpqrstvwxyz", 5)),
DisplayName: resp.User.Name, DisplayName: resp.User.Name,
Email: resp.User.Email, Email: resp.User.Email,
} }

View File

@ -65,7 +65,7 @@ form dd {
</ul>{{end}} </ul>{{end}}
<div id="billing"> <div id="billing">
<form action="/oauth/signup" method="post" style="text-align: center;margin-top:1em;" onsubmit="disableSubmit()"> <form action="/oauth/signup" method="post" style="text-align: center;margin-top:1em;" onsubmit="return disableSubmit()">
<input type="hidden" name="access_token" value="{{ .AccessToken }}" /> <input type="hidden" name="access_token" value="{{ .AccessToken }}" />
<input type="hidden" name="token_username" value="{{ .TokenUsername }}" /> <input type="hidden" name="token_username" value="{{ .TokenUsername }}" />
<input type="hidden" name="token_alias" value="{{ .TokenAlias }}" /> <input type="hidden" name="token_alias" value="{{ .TokenAlias }}" />
@ -77,15 +77,15 @@ form dd {
<dl class="billing"> <dl class="billing">
<label> <label>
<dt>Blog Title</dt> <dt>Display Name</dt>
<dd> <dd>
<input type="text" style="width: 100%; box-sizing: border-box;" name="alias" placeholder="Alias"{{ if .Alias }} value="{{.Alias}}"{{ end }} /> <input type="text" style="width: 100%; box-sizing: border-box;" name="alias" placeholder="Name"{{ if .Alias }} value="{{.Alias}}"{{ end }} />
</dd> </dd>
</label> </label>
<label> <label>
<dt>Username</dt> <dt>Username</dt>
<dd> <dd>
<input type="text" name="username" style="width: 100%; box-sizing: border-box;" placeholder="Username" value="{{.Username}}" /><br /> <input type="text" id="username" name="username" style="width: 100%; box-sizing: border-box;" placeholder="Username" value="{{.LoginUsername}}" /><br />
{{if .Federation}}<p id="alias-site" class="demo">@<strong>your-username</strong>@{{.FriendlyHost}}</p>{{else}}<p id="alias-site" class="demo">{{.FriendlyHost}}/<strong>your-username</strong></p>{{end}} {{if .Federation}}<p id="alias-site" class="demo">@<strong>your-username</strong>@{{.FriendlyHost}}</p>{{else}}<p id="alias-site" class="demo">{{.FriendlyHost}}/<strong>your-username</strong></p>{{end}}
</dd> </dd>
</label> </label>
@ -95,12 +95,6 @@ form dd {
<input type="text" name="email" style="width: 100%; box-sizing: border-box;" placeholder="Email"{{ if .Email }} value="{{.Email}}"{{ end }} /> <input type="text" name="email" style="width: 100%; box-sizing: border-box;" placeholder="Email"{{ if .Email }} value="{{.Email}}"{{ end }} />
</dd> </dd>
</label> </label>
<label>
<dt>Password</dt>
<dd>
<input type="password" name="password" style="width: 100%; box-sizing: border-box;" placeholder="Password" /><br />
</dd>
</label>
<dt> <dt>
<input type="submit" id="btn-login" value="Login" /> <input type="submit" id="btn-login" value="Login" />
</dt> </dt>
@ -108,11 +102,73 @@ form dd {
</form> </form>
</div> </div>
<script type="text/javascript" src="/js/h.js"></script>
<script type="text/javascript"> <script type="text/javascript">
// Copied from signup.tmpl
// NOTE: this element is named "alias" on signup.tmpl and "username" here
var $alias = H.getEl('username');
function disableSubmit() { function disableSubmit() {
// Validate input
if (!aliasOK) {
var $a = $alias;
$a.el.className = 'error';
$a.el.focus();
$a.el.scrollIntoView();
return false;
}
var $btn = document.getElementById("btn-login"); var $btn = document.getElementById("btn-login");
$btn.value = "Logging in..."; $btn.value = "Logging in...";
$btn.disabled = true; $btn.disabled = true;
return true;
} }
// Copied from signup.tmpl
var $aliasSite = document.getElementById('alias-site');
var aliasOK = true;
var typingTimer;
var doneTypingInterval = 750;
var doneTyping = function() {
// Check on username
var alias = $alias.el.value;
if (alias != "") {
var params = {
username: alias
};
var http = new XMLHttpRequest();
http.open("POST", '/api/alias', true);
// Send the proper header information along with the request
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = function() {
if (http.readyState == 4) {
data = JSON.parse(http.responseText);
if (http.status == 200) {
aliasOK = true;
$alias.removeClass('error');
$aliasSite.className = $aliasSite.className.replace(/(?:^|\s)demo(?!\S)/g, '');
$aliasSite.className = $aliasSite.className.replace(/(?:^|\s)error(?!\S)/g, '');
$aliasSite.innerHTML = '{{ if .Federation }}@<strong>' + data.data + '</strong>@{{.FriendlyHost}}{{ else }}{{.FriendlyHost}}/<strong>' + data.data + '</strong>/{{ end }}';
} else {
aliasOK = false;
$alias.setClass('error');
$aliasSite.className = 'error';
$aliasSite.textContent = data.error_msg;
}
}
}
http.send(JSON.stringify(params));
} else {
$aliasSite.className += ' demo';
$aliasSite.innerHTML = '{{ if .Federation }}@<strong>your-username</strong>@{{.FriendlyHost}}{{ else }}{{.FriendlyHost}}/<strong>your-username</strong>/{{ end }}';
}
};
$alias.on('keyup input', function() {
clearTimeout(typingTimer);
typingTimer = setTimeout(doneTyping, doneTypingInterval);
});
doneTyping();
</script> </script>
{{end}} {{end}}