api,frontend: add commenter password resets
This commit is contained in:
parent
36fea6e95b
commit
85456a019e
@ -46,3 +46,4 @@ var errorDatabaseMigration = errors.New("Encountered error applying database mig
|
|||||||
var errorNoSuchUnsubscribeSecretHex = errors.New("Invalid unsubscribe link.")
|
var errorNoSuchUnsubscribeSecretHex = errors.New("Invalid unsubscribe link.")
|
||||||
var errorEmptyPaths = errors.New("Empty paths field.")
|
var errorEmptyPaths = errors.New("Empty paths field.")
|
||||||
var errorInvalidDomain = errors.New("Invalid domain name. Do not include the URL path after the forward slash.")
|
var errorInvalidDomain = errors.New("Invalid domain name. Do not include the URL path after the forward slash.")
|
||||||
|
var errorInvalidEntity = errors.New("That entity does not exist.")
|
||||||
|
97
api/forgot.go
Normal file
97
api/forgot.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func forgot(email string, entity string) error {
|
||||||
|
if email == "" {
|
||||||
|
return errorMissingField
|
||||||
|
}
|
||||||
|
|
||||||
|
if entity != "owner" && entity != "commenter" {
|
||||||
|
return errorInvalidEntity
|
||||||
|
}
|
||||||
|
|
||||||
|
if !smtpConfigured {
|
||||||
|
return errorSmtpNotConfigured
|
||||||
|
}
|
||||||
|
|
||||||
|
var hex string
|
||||||
|
var name string
|
||||||
|
if entity == "owner" {
|
||||||
|
o, err := ownerGetByEmail(email)
|
||||||
|
if err != nil {
|
||||||
|
if err == errorNoSuchEmail {
|
||||||
|
// TODO: use a more random time instead.
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
logger.Errorf("cannot get owner by email: %v", err)
|
||||||
|
return errorInternal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hex = o.OwnerHex
|
||||||
|
name = o.Name
|
||||||
|
} else {
|
||||||
|
c, err := commenterGetByEmail("commento", email)
|
||||||
|
if err != nil {
|
||||||
|
if err == errorNoSuchEmail {
|
||||||
|
// TODO: use a more random time instead.
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
logger.Errorf("cannot get commenter by email: %v", err)
|
||||||
|
return errorInternal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hex = c.CommenterHex
|
||||||
|
name = c.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
resetHex, err := randomHex(32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var statement string
|
||||||
|
|
||||||
|
statement = `
|
||||||
|
INSERT INTO
|
||||||
|
resetHexes (resetHex, hex, entity, sendDate)
|
||||||
|
VALUES ($1, $2, $3, $4 );
|
||||||
|
`
|
||||||
|
_, err = db.Exec(statement, resetHex, hex, entity, time.Now().UTC())
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("cannot insert resetHex: %v", err)
|
||||||
|
return errorInternal
|
||||||
|
}
|
||||||
|
|
||||||
|
err = smtpResetHex(email, name, resetHex)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func forgotHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
type request struct {
|
||||||
|
Email *string `json:"email"`
|
||||||
|
Entity *string `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var x request
|
||||||
|
if err := bodyUnmarshal(r, &x); err != nil {
|
||||||
|
bodyMarshal(w, response{"success": false, "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := forgot(*x.Email, *x.Entity); err != nil {
|
||||||
|
bodyMarshal(w, response{"success": false, "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyMarshal(w, response{"success": true})
|
||||||
|
}
|
@ -1,70 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ownerSendResetHex(email string) error {
|
|
||||||
if email == "" {
|
|
||||||
return errorMissingField
|
|
||||||
}
|
|
||||||
|
|
||||||
if !smtpConfigured {
|
|
||||||
return errorSmtpNotConfigured
|
|
||||||
}
|
|
||||||
|
|
||||||
o, err := ownerGetByEmail(email)
|
|
||||||
if err != nil {
|
|
||||||
if err == errorNoSuchEmail {
|
|
||||||
// TODO: use a more random time instead.
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
logger.Errorf("cannot get owner by email: %v", err)
|
|
||||||
return errorInternal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resetHex, err := randomHex(32)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
statement := `
|
|
||||||
INSERT INTO
|
|
||||||
ownerResetHexes (resetHex, ownerHex, sendDate)
|
|
||||||
VALUES ($1, $2, $3 );
|
|
||||||
`
|
|
||||||
_, err = db.Exec(statement, resetHex, o.OwnerHex, time.Now().UTC())
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("cannot insert resetHex: %v", err)
|
|
||||||
return errorInternal
|
|
||||||
}
|
|
||||||
|
|
||||||
err = smtpOwnerResetHex(email, o.Name, resetHex)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ownerSendResetHexHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
type request struct {
|
|
||||||
Email *string `json:"email"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var x request
|
|
||||||
if err := bodyUnmarshal(r, &x); err != nil {
|
|
||||||
bodyMarshal(w, response{"success": false, "message": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ownerSendResetHex(*x.Email); err != nil {
|
|
||||||
bodyMarshal(w, response{"success": false, "message": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bodyMarshal(w, response{"success": true})
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ownerResetPassword(resetHex string, password string) error {
|
|
||||||
if resetHex == "" || password == "" {
|
|
||||||
return errorMissingField
|
|
||||||
}
|
|
||||||
|
|
||||||
passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("cannot generate hash from password: %v\n", err)
|
|
||||||
return errorInternal
|
|
||||||
}
|
|
||||||
|
|
||||||
statement := `
|
|
||||||
UPDATE owners SET passwordHash=$1
|
|
||||||
WHERE ownerHex = (
|
|
||||||
SELECT ownerHex
|
|
||||||
FROM ownerResetHexes
|
|
||||||
WHERE resetHex=$2
|
|
||||||
);
|
|
||||||
`
|
|
||||||
res, err := db.Exec(statement, string(passwordHash), resetHex)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("cannot change user's password: %v\n", err)
|
|
||||||
return errorInternal
|
|
||||||
}
|
|
||||||
|
|
||||||
count, err := res.RowsAffected()
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("cannot count rows affected: %v\n", err)
|
|
||||||
return errorInternal
|
|
||||||
}
|
|
||||||
|
|
||||||
if count == 0 {
|
|
||||||
return errorNoSuchResetToken
|
|
||||||
}
|
|
||||||
|
|
||||||
statement = `
|
|
||||||
DELETE FROM ownerResetHexes
|
|
||||||
WHERE resetHex=$1;
|
|
||||||
`
|
|
||||||
_, err = db.Exec(statement, resetHex)
|
|
||||||
if err != nil {
|
|
||||||
logger.Warningf("cannot remove reset token: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ownerResetPasswordHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
type request struct {
|
|
||||||
ResetHex *string `json:"resetHex"`
|
|
||||||
Password *string `json:"password"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var x request
|
|
||||||
if err := bodyUnmarshal(r, &x); err != nil {
|
|
||||||
bodyMarshal(w, response{"success": false, "message": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ownerResetPassword(*x.ResetHex, *x.Password); err != nil {
|
|
||||||
bodyMarshal(w, response{"success": false, "message": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bodyMarshal(w, response{"success": true})
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestOwnerResetPasswordBasics(t *testing.T) {
|
|
||||||
failTestOnError(t, setupTestEnv())
|
|
||||||
|
|
||||||
ownerHex, _ := ownerNew("test@example.com", "Test", "hunter2")
|
|
||||||
|
|
||||||
resetHex, _ := randomHex(32)
|
|
||||||
|
|
||||||
statement := `
|
|
||||||
INSERT INTO
|
|
||||||
ownerResetHexes (resetHex, ownerHex, sendDate)
|
|
||||||
VALUES ($1, $2, $3 );
|
|
||||||
`
|
|
||||||
_, err := db.Exec(statement, resetHex, ownerHex, time.Now().UTC())
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error inserting resetHex: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = ownerResetPassword(resetHex, "hunter3"); err != nil {
|
|
||||||
t.Errorf("unexpected error resetting password: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := ownerLogin("test@example.com", "hunter2"); err == nil {
|
|
||||||
t.Errorf("expected error not found when given old password")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := ownerLogin("test@example.com", "hunter3"); err != nil {
|
|
||||||
t.Errorf("unexpected error when logging in: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
82
api/reset.go
Normal file
82
api/reset.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func reset(resetHex string, password string) (string, error) {
|
||||||
|
if resetHex == "" || password == "" {
|
||||||
|
return "", errorMissingField
|
||||||
|
}
|
||||||
|
|
||||||
|
statement := `
|
||||||
|
SELECT hex, entity
|
||||||
|
FROM resetHexes
|
||||||
|
WHERE resetHex = $1;
|
||||||
|
`
|
||||||
|
row := db.QueryRow(statement, resetHex)
|
||||||
|
|
||||||
|
var hex string
|
||||||
|
var entity string
|
||||||
|
if err := row.Scan(&hex, &entity); err != nil {
|
||||||
|
// TODO: is this the only error?
|
||||||
|
return "", errorNoSuchResetToken
|
||||||
|
}
|
||||||
|
|
||||||
|
passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("cannot generate hash from password: %v\n", err)
|
||||||
|
return "", errorInternal
|
||||||
|
}
|
||||||
|
|
||||||
|
if entity == "owner" {
|
||||||
|
statement = `
|
||||||
|
UPDATE owners SET passwordHash = $1
|
||||||
|
WHERE ownerHex = $2;
|
||||||
|
`
|
||||||
|
} else {
|
||||||
|
statement = `
|
||||||
|
UPDATE commenters SET passwordHash = $1
|
||||||
|
WHERE commenterHex = $2;
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.Exec(statement, string(passwordHash), hex)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("cannot change %s's password: %v\n", entity, err)
|
||||||
|
return "", errorInternal
|
||||||
|
}
|
||||||
|
|
||||||
|
statement = `
|
||||||
|
DELETE FROM resetHexes
|
||||||
|
WHERE resetHex = $1;
|
||||||
|
`
|
||||||
|
_, err = db.Exec(statement, resetHex)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warningf("cannot remove resetHex: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
type request struct {
|
||||||
|
ResetHex *string `json:"resetHex"`
|
||||||
|
Password *string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var x request
|
||||||
|
if err := bodyUnmarshal(r, &x); err != nil {
|
||||||
|
bodyMarshal(w, response{"success": false, "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entity, err := reset(*x.ResetHex, *x.Password)
|
||||||
|
if err != nil {
|
||||||
|
bodyMarshal(w, response{"success": false, "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyMarshal(w, response{"success": true, "entity": entity})
|
||||||
|
}
|
@ -8,8 +8,6 @@ func apiRouterInit(router *mux.Router) error {
|
|||||||
router.HandleFunc("/api/owner/new", ownerNewHandler).Methods("POST")
|
router.HandleFunc("/api/owner/new", ownerNewHandler).Methods("POST")
|
||||||
router.HandleFunc("/api/owner/confirm-hex", ownerConfirmHexHandler).Methods("GET")
|
router.HandleFunc("/api/owner/confirm-hex", ownerConfirmHexHandler).Methods("GET")
|
||||||
router.HandleFunc("/api/owner/login", ownerLoginHandler).Methods("POST")
|
router.HandleFunc("/api/owner/login", ownerLoginHandler).Methods("POST")
|
||||||
router.HandleFunc("/api/owner/send-reset-hex", ownerSendResetHexHandler).Methods("POST")
|
|
||||||
router.HandleFunc("/api/owner/reset-password", ownerResetPasswordHandler).Methods("POST")
|
|
||||||
router.HandleFunc("/api/owner/self", ownerSelfHandler).Methods("POST")
|
router.HandleFunc("/api/owner/self", ownerSelfHandler).Methods("POST")
|
||||||
|
|
||||||
router.HandleFunc("/api/domain/new", domainNewHandler).Methods("POST")
|
router.HandleFunc("/api/domain/new", domainNewHandler).Methods("POST")
|
||||||
@ -31,6 +29,9 @@ func apiRouterInit(router *mux.Router) error {
|
|||||||
router.HandleFunc("/api/commenter/self", commenterSelfHandler).Methods("POST")
|
router.HandleFunc("/api/commenter/self", commenterSelfHandler).Methods("POST")
|
||||||
router.HandleFunc("/api/commenter/photo", commenterPhotoHandler).Methods("GET")
|
router.HandleFunc("/api/commenter/photo", commenterPhotoHandler).Methods("GET")
|
||||||
|
|
||||||
|
router.HandleFunc("/api/forgot", forgotHandler).Methods("POST")
|
||||||
|
router.HandleFunc("/api/reset", resetHandler).Methods("POST")
|
||||||
|
|
||||||
router.HandleFunc("/api/email/get", emailGetHandler).Methods("POST")
|
router.HandleFunc("/api/email/get", emailGetHandler).Methods("POST")
|
||||||
router.HandleFunc("/api/email/update", emailUpdateHandler).Methods("POST")
|
router.HandleFunc("/api/email/update", emailUpdateHandler).Methods("POST")
|
||||||
router.HandleFunc("/api/email/moderate", emailModerateHandler).Methods("GET")
|
router.HandleFunc("/api/email/moderate", emailModerateHandler).Methods("GET")
|
||||||
|
@ -96,7 +96,7 @@ func staticRouterInit(router *mux.Router) error {
|
|||||||
pages := []string{
|
pages := []string{
|
||||||
"/login",
|
"/login",
|
||||||
"/forgot",
|
"/forgot",
|
||||||
"/reset-password",
|
"/reset",
|
||||||
"/signup",
|
"/signup",
|
||||||
"/confirm-email",
|
"/confirm-email",
|
||||||
"/unsubscribe",
|
"/unsubscribe",
|
||||||
|
@ -6,17 +6,17 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ownerResetHexPlugs struct {
|
type resetHexPlugs struct {
|
||||||
Origin string
|
Origin string
|
||||||
ResetHex string
|
ResetHex string
|
||||||
}
|
}
|
||||||
|
|
||||||
func smtpOwnerResetHex(to string, toName string, resetHex string) error {
|
func smtpResetHex(to string, toName string, resetHex string) error {
|
||||||
var header bytes.Buffer
|
var header bytes.Buffer
|
||||||
headerTemplate.Execute(&header, &headerPlugs{FromAddress: os.Getenv("SMTP_FROM_ADDRESS"), ToAddress: to, ToName: toName, Subject: "Reset your password"})
|
headerTemplate.Execute(&header, &headerPlugs{FromAddress: os.Getenv("SMTP_FROM_ADDRESS"), ToAddress: to, ToName: toName, Subject: "Reset your password"})
|
||||||
|
|
||||||
var body bytes.Buffer
|
var body bytes.Buffer
|
||||||
templates["reset-hex"].Execute(&body, &ownerResetHexPlugs{Origin: os.Getenv("ORIGIN"), ResetHex: resetHex})
|
templates["reset-hex"].Execute(&body, &resetHexPlugs{Origin: os.Getenv("ORIGIN"), ResetHex: resetHex})
|
||||||
|
|
||||||
err := smtp.SendMail(os.Getenv("SMTP_HOST")+":"+os.Getenv("SMTP_PORT"), smtpAuth, os.Getenv("SMTP_FROM_ADDRESS"), []string{to}, concat(header, body))
|
err := smtp.SendMail(os.Getenv("SMTP_HOST")+":"+os.Getenv("SMTP_PORT"), smtpAuth, os.Getenv("SMTP_FROM_ADDRESS"), []string{to}, concat(header, body))
|
||||||
if err != nil {
|
if err != nil {
|
8
db/20190606000842-reset-hex.sql
Normal file
8
db/20190606000842-reset-hex.sql
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
-- Create the resetHexes table
|
||||||
|
|
||||||
|
ALTER TABLE ownerResetHexes RENAME TO resetHexes;
|
||||||
|
|
||||||
|
ALTER TABLE resetHexes RENAME ownerHex TO hex;
|
||||||
|
|
||||||
|
ALTER TABLE resetHexes
|
||||||
|
ADD entity TEXT NOT NULL DEFAULT 'owner';
|
@ -22,8 +22,8 @@
|
|||||||
var ID_LOGIN_BOX_NAME_INPUT = "commento-login-box-name-input";
|
var ID_LOGIN_BOX_NAME_INPUT = "commento-login-box-name-input";
|
||||||
var ID_LOGIN_BOX_WEBSITE_INPUT = "commento-login-box-website-input";
|
var ID_LOGIN_BOX_WEBSITE_INPUT = "commento-login-box-website-input";
|
||||||
var ID_LOGIN_BOX_EMAIL_BUTTON = "commento-login-box-email-button";
|
var ID_LOGIN_BOX_EMAIL_BUTTON = "commento-login-box-email-button";
|
||||||
|
var ID_LOGIN_BOX_FORGOT_LINK_CONTAINER = "commento-login-box-forgot-link-container";
|
||||||
var ID_LOGIN_BOX_LOGIN_LINK_CONTAINER = "commento-login-box-login-link-container";
|
var ID_LOGIN_BOX_LOGIN_LINK_CONTAINER = "commento-login-box-login-link-container";
|
||||||
var ID_LOGIN_BOX_LOGIN_LINK = "commento-login-box-login-link";
|
|
||||||
var ID_LOGIN_BOX_SSO_PRETEXT = "commento-login-box-sso-pretext";
|
var ID_LOGIN_BOX_SSO_PRETEXT = "commento-login-box-sso-pretext";
|
||||||
var ID_LOGIN_BOX_SSO_BUTTON_CONTAINER = "commento-login-box-sso-buttton-container";
|
var ID_LOGIN_BOX_SSO_BUTTON_CONTAINER = "commento-login-box-sso-buttton-container";
|
||||||
var ID_LOGIN_BOX_HR1 = "commento-login-box-hr1";
|
var ID_LOGIN_BOX_HR1 = "commento-login-box-hr1";
|
||||||
@ -1448,6 +1448,8 @@
|
|||||||
var email = create("div");
|
var email = create("div");
|
||||||
var emailInput = create("input");
|
var emailInput = create("input");
|
||||||
var emailButton = create("button");
|
var emailButton = create("button");
|
||||||
|
var forgotLinkContainer = create("div");
|
||||||
|
var forgotLink = create("a");
|
||||||
var loginLinkContainer = create("div");
|
var loginLinkContainer = create("div");
|
||||||
var loginLink = create("a");
|
var loginLink = create("a");
|
||||||
var close = create("div");
|
var close = create("div");
|
||||||
@ -1456,7 +1458,7 @@
|
|||||||
emailSubtitle.id = ID_LOGIN_BOX_EMAIL_SUBTITLE;
|
emailSubtitle.id = ID_LOGIN_BOX_EMAIL_SUBTITLE;
|
||||||
emailInput.id = ID_LOGIN_BOX_EMAIL_INPUT;
|
emailInput.id = ID_LOGIN_BOX_EMAIL_INPUT;
|
||||||
emailButton.id = ID_LOGIN_BOX_EMAIL_BUTTON;
|
emailButton.id = ID_LOGIN_BOX_EMAIL_BUTTON;
|
||||||
loginLink.id = ID_LOGIN_BOX_LOGIN_LINK;
|
forgotLinkContainer.id = ID_LOGIN_BOX_FORGOT_LINK_CONTAINER
|
||||||
loginLinkContainer.id = ID_LOGIN_BOX_LOGIN_LINK_CONTAINER;
|
loginLinkContainer.id = ID_LOGIN_BOX_LOGIN_LINK_CONTAINER;
|
||||||
ssoButtonContainer.id = ID_LOGIN_BOX_SSO_BUTTON_CONTAINER;
|
ssoButtonContainer.id = ID_LOGIN_BOX_SSO_BUTTON_CONTAINER;
|
||||||
ssoSubtitle.id = ID_LOGIN_BOX_SSO_PRETEXT;
|
ssoSubtitle.id = ID_LOGIN_BOX_SSO_PRETEXT;
|
||||||
@ -1472,6 +1474,8 @@
|
|||||||
classAdd(email, "email");
|
classAdd(email, "email");
|
||||||
classAdd(emailInput, "input");
|
classAdd(emailInput, "input");
|
||||||
classAdd(emailButton, "email-button");
|
classAdd(emailButton, "email-button");
|
||||||
|
classAdd(forgotLinkContainer, "forgot-link-container");
|
||||||
|
classAdd(forgotLink, "forgot-link");
|
||||||
classAdd(loginLinkContainer, "login-link-container");
|
classAdd(loginLinkContainer, "login-link-container");
|
||||||
classAdd(loginLink, "login-link");
|
classAdd(loginLink, "login-link");
|
||||||
classAdd(ssoSubtitle, "login-box-subtitle");
|
classAdd(ssoSubtitle, "login-box-subtitle");
|
||||||
@ -1483,6 +1487,7 @@
|
|||||||
classAdd(close, "login-box-close");
|
classAdd(close, "login-box-close");
|
||||||
classAdd(root, "root-min-height");
|
classAdd(root, "root-min-height");
|
||||||
|
|
||||||
|
forgotLink.innerText = "Forgot your password?";
|
||||||
loginLink.innerText = "Don't have an account? Sign up.";
|
loginLink.innerText = "Don't have an account? Sign up.";
|
||||||
emailSubtitle.innerText = "Login with your email address";
|
emailSubtitle.innerText = "Login with your email address";
|
||||||
emailButton.innerText = "Continue";
|
emailButton.innerText = "Continue";
|
||||||
@ -1490,6 +1495,7 @@
|
|||||||
ssoSubtitle.innerText = "Proceed with " + parent.location.host + " authentication";
|
ssoSubtitle.innerText = "Proceed with " + parent.location.host + " authentication";
|
||||||
|
|
||||||
onclick(emailButton, global.passwordAsk, id);
|
onclick(emailButton, global.passwordAsk, id);
|
||||||
|
onclick(forgotLink, global.forgotPassword, id);
|
||||||
onclick(loginLink, global.popupSwitch, id);
|
onclick(loginLink, global.popupSwitch, id);
|
||||||
onclick(close, global.loginBoxClose);
|
onclick(close, global.loginBoxClose);
|
||||||
|
|
||||||
@ -1522,7 +1528,7 @@
|
|||||||
classAdd(button, "button");
|
classAdd(button, "button");
|
||||||
classAdd(button, "sso-button");
|
classAdd(button, "sso-button");
|
||||||
|
|
||||||
button.innerText = "Login with Single Sign-On";
|
button.innerText = "Single Sign-On";
|
||||||
|
|
||||||
onclick(button, global.commentoAuth, {"provider": "sso", "id": id});
|
onclick(button, global.commentoAuth, {"provider": "sso", "id": id});
|
||||||
|
|
||||||
@ -1549,6 +1555,8 @@
|
|||||||
append(email, emailButton);
|
append(email, emailButton);
|
||||||
append(emailContainer, email);
|
append(emailContainer, email);
|
||||||
|
|
||||||
|
append(forgotLinkContainer, forgotLink);
|
||||||
|
|
||||||
append(loginLinkContainer, loginLink);
|
append(loginLinkContainer, loginLink);
|
||||||
|
|
||||||
if (numOauthConfigured > 0 && configuredOauths["commento"]) {
|
if (numOauthConfigured > 0 && configuredOauths["commento"]) {
|
||||||
@ -1558,6 +1566,7 @@
|
|||||||
if (configuredOauths["commento"]) {
|
if (configuredOauths["commento"]) {
|
||||||
append(loginBox, emailSubtitle);
|
append(loginBox, emailSubtitle);
|
||||||
append(loginBox, emailContainer);
|
append(loginBox, emailContainer);
|
||||||
|
append(loginBox, forgotLinkContainer);
|
||||||
append(loginBox, loginLinkContainer);
|
append(loginBox, loginLinkContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1569,9 +1578,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
global.forgotPassword = function() {
|
||||||
|
var popup = window.open("", "_blank");
|
||||||
|
popup.location = origin + "/forgot?commenter=true";
|
||||||
|
global.loginBoxClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
global.popupSwitch = function(id) {
|
global.popupSwitch = function(id) {
|
||||||
var emailSubtitle = $(ID_LOGIN_BOX_EMAIL_SUBTITLE);
|
var emailSubtitle = $(ID_LOGIN_BOX_EMAIL_SUBTITLE);
|
||||||
var loginLink = $(ID_LOGIN_BOX_LOGIN_LINK);
|
|
||||||
|
|
||||||
if (oauthButtonsShown) {
|
if (oauthButtonsShown) {
|
||||||
remove($(ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER));
|
remove($(ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER));
|
||||||
@ -1587,7 +1602,9 @@
|
|||||||
remove($(ID_LOGIN_BOX_HR2));
|
remove($(ID_LOGIN_BOX_HR2));
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(loginLink);
|
remove($(ID_LOGIN_BOX_LOGIN_LINK_CONTAINER));
|
||||||
|
remove($(ID_LOGIN_BOX_FORGOT_LINK_CONTAINER));
|
||||||
|
|
||||||
emailSubtitle.innerText = "Create an account";
|
emailSubtitle.innerText = "Create an account";
|
||||||
popupBoxType = "signup";
|
popupBoxType = "signup";
|
||||||
global.passwordAsk(id);
|
global.passwordAsk(id);
|
||||||
@ -1665,21 +1682,16 @@
|
|||||||
global.passwordAsk = function(id) {
|
global.passwordAsk = function(id) {
|
||||||
var loginBox = $(ID_LOGIN_BOX);
|
var loginBox = $(ID_LOGIN_BOX);
|
||||||
var subtitle = $(ID_LOGIN_BOX_EMAIL_SUBTITLE);
|
var subtitle = $(ID_LOGIN_BOX_EMAIL_SUBTITLE);
|
||||||
var emailButton = $(ID_LOGIN_BOX_EMAIL_BUTTON);
|
|
||||||
var loginLinkContainer = $(ID_LOGIN_BOX_LOGIN_LINK_CONTAINER);
|
|
||||||
var hr1 = $(ID_LOGIN_BOX_HR1);
|
|
||||||
var hr2 = $(ID_LOGIN_BOX_HR2);
|
|
||||||
var oauthButtonsContainer = $(ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER);
|
|
||||||
var oauthPretext = $(ID_LOGIN_BOX_OAUTH_PRETEXT);
|
|
||||||
|
|
||||||
remove(emailButton);
|
remove($(ID_LOGIN_BOX_EMAIL_BUTTON));
|
||||||
remove(loginLinkContainer);
|
remove($(ID_LOGIN_BOX_LOGIN_LINK_CONTAINER));
|
||||||
|
remove($(ID_LOGIN_BOX_FORGOT_LINK_CONTAINER));
|
||||||
if (oauthButtonsShown) {
|
if (oauthButtonsShown) {
|
||||||
if (configuredOauths.length > 0) {
|
if (configuredOauths.length > 0) {
|
||||||
remove(hr1);
|
remove($(ID_LOGIN_BOX_HR1));
|
||||||
remove(hr2);
|
remove($(ID_LOGIN_BOX_HR2));
|
||||||
remove(oauthPretext);
|
remove($(ID_LOGIN_BOX_OAUTH_PRETEXT));
|
||||||
remove(oauthButtonsContainer);
|
remove($(ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,12 +16,18 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var entity = "owner";
|
||||||
|
if (global.paramGet("commenter") === "true") {
|
||||||
|
entity = "commenter";
|
||||||
|
}
|
||||||
|
|
||||||
var json = {
|
var json = {
|
||||||
"email": $("#email").val(),
|
"email": $("#email").val(),
|
||||||
|
"entity": entity,
|
||||||
};
|
};
|
||||||
|
|
||||||
global.buttonDisable("#reset-button");
|
global.buttonDisable("#reset-button");
|
||||||
global.post(global.origin + "/api/owner/send-reset-hex", json, function(resp) {
|
global.post(global.origin + "/api/forgot", json, function(resp) {
|
||||||
global.buttonEnable("#reset-button");
|
global.buttonEnable("#reset-button");
|
||||||
|
|
||||||
global.textSet("#err", "");
|
global.textSet("#err", "");
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
global.buttonDisable("#reset-button");
|
global.buttonDisable("#reset-button");
|
||||||
global.post(global.origin + "/api/owner/reset-password", json, function(resp) {
|
global.post(global.origin + "/api/reset", json, function(resp) {
|
||||||
global.buttonEnable("#reset-button");
|
global.buttonEnable("#reset-button");
|
||||||
|
|
||||||
global.textSet("#err", "");
|
global.textSet("#err", "");
|
||||||
@ -33,8 +33,14 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resp.entity === "owner") {
|
||||||
document.location = global.origin + "/login?changed=true";
|
document.location = global.origin + "/login?changed=true";
|
||||||
|
} else {
|
||||||
|
$("#msg").html("Your password has been reset. You may close this window and try logging in again.");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.close();
|
||||||
|
|
||||||
} (window.commento, document));
|
} (window.commento, document));
|
||||||
|
@ -38,16 +38,24 @@
|
|||||||
|
|
||||||
@import "email-main.scss";
|
@import "email-main.scss";
|
||||||
|
|
||||||
|
.commento-forgot-link-container,
|
||||||
.commento-login-link-container {
|
.commento-login-link-container {
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
width: calc(100% - 32px);
|
width: calc(100% - 32px);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-forgot-link,
|
||||||
.commento-login-link {
|
.commento-login-link {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.commento-forgot-link {
|
||||||
|
font-size: 13px;
|
||||||
|
color: $gray-6;
|
||||||
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commento-login-box-close {
|
.commento-login-box-close {
|
||||||
|
@ -2,6 +2,6 @@ Hi,
|
|||||||
|
|
||||||
Someone (probably you) recently initiated the procedure to reset your Commento account password. To do this, use the link below:
|
Someone (probably you) recently initiated the procedure to reset your Commento account password. To do this, use the link below:
|
||||||
|
|
||||||
{{.Origin}}/reset-password?hex={{.ResetHex}}
|
{{.Origin}}/reset?hex={{.ResetHex}}
|
||||||
|
|
||||||
If you did not initiate this request, you can safely ignore this email.
|
If you did not initiate this request, you can safely ignore this email.
|
||||||
|
Loading…
Reference in New Issue
Block a user