Add change password command and improve account page in settings
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
c85ff1b5b7
commit
d4f4af313d
4 changed files with 156 additions and 15 deletions
|
@ -62,6 +62,7 @@ func main() {
|
|||
commands.ResampleCommand,
|
||||
commands.MigrateCommand,
|
||||
commands.ConfigCommand,
|
||||
commands.PasswdCommand,
|
||||
commands.VersionCommand,
|
||||
commands.StatusCommand,
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
<template>
|
||||
<div class="p-tab p-settings-account">
|
||||
<v-form lazy-validation dense
|
||||
ref="form" class="form-password" accept-charset="UTF-8">
|
||||
<v-form dense ref="form" class="form-password" accept-charset="UTF-8">
|
||||
<v-card flat tile class="ma-2 application">
|
||||
<v-card-actions>
|
||||
<v-layout wrap align-top>
|
||||
<v-flex xs12 class="px-2 pt-2 pb-4">
|
||||
<v-flex xs12 class="pa-2">
|
||||
<v-text-field
|
||||
hide-details required
|
||||
:disabled="busy"
|
||||
browser-autocomplete="off"
|
||||
label="Current Password"
|
||||
:label="$gettext('Current Password')"
|
||||
color="secondary-dark"
|
||||
type="password"
|
||||
placeholder="••••••••"
|
||||
|
@ -20,30 +19,39 @@
|
|||
|
||||
<v-flex xs12 class="pa-2">
|
||||
<v-text-field
|
||||
hide-details required
|
||||
required counter persistent-hint
|
||||
:disabled="busy"
|
||||
browser-autocomplete="off"
|
||||
label="New Password"
|
||||
:label="$gettext('New Password')"
|
||||
color="secondary-dark"
|
||||
type="password"
|
||||
placeholder="••••••••"
|
||||
v-model="newPassword"
|
||||
:hint="$gettext('At least 6 characters.')"
|
||||
></v-text-field>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 class="pa-2">
|
||||
<v-text-field
|
||||
hide-details required
|
||||
required counter persistent-hint
|
||||
:disabled="busy"
|
||||
browser-autocomplete="off"
|
||||
label="Confirm Password"
|
||||
:label="$gettext('Retype Password')"
|
||||
color="secondary-dark"
|
||||
type="password"
|
||||
placeholder="••••••••"
|
||||
v-model="confirmPassword"
|
||||
:hint="$gettext('Please confirm your new password.')"
|
||||
></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="px-2 pt-4 pb-2">
|
||||
|
||||
<v-flex xs12 class="pa-2">
|
||||
<p class="caption pa-0">
|
||||
<translate>Note: Updating the password will not revoke access from already authenticated users.</translate>
|
||||
</p>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 class="pa-2">
|
||||
<v-btn depressed color="secondary-dark"
|
||||
@click.stop="confirm"
|
||||
:disabled="disabled()"
|
||||
|
@ -73,7 +81,7 @@
|
|||
},
|
||||
methods: {
|
||||
disabled() {
|
||||
return (this.busy || this.oldPassword === "" || this.newPassword === "" || (this.newPassword !== this.confirmPassword));
|
||||
return (this.busy || this.oldPassword === "" || this.newPassword.length < 6 || (this.newPassword !== this.confirmPassword));
|
||||
},
|
||||
confirm() {
|
||||
this.busy = true;
|
||||
|
|
128
internal/commands/passwd.go
Normal file
128
internal/commands/passwd.go
Normal file
|
@ -0,0 +1,128 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/config"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// PasswdCommand updates a password.
|
||||
var PasswdCommand = cli.Command{
|
||||
Name: "passwd",
|
||||
Usage: "Changes the admin password",
|
||||
Action: passwdAction,
|
||||
}
|
||||
|
||||
// passwdAction updates a password.
|
||||
func passwdAction(ctx *cli.Context) error {
|
||||
conf := config.NewConfig(ctx)
|
||||
|
||||
cctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
if err := conf.Init(cctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conf.InitDb()
|
||||
|
||||
user := entity.Admin
|
||||
|
||||
log.Infof("please enter a new password for %s (at least 6 characters)\n", txt.Quote(user.UserName))
|
||||
|
||||
newPassword := getPassword("New Password: ")
|
||||
|
||||
if len(newPassword) < 6 {
|
||||
return errors.New("new password is too short, please try again")
|
||||
}
|
||||
|
||||
retypePassword := getPassword("Retype Password: ")
|
||||
|
||||
if newPassword != retypePassword {
|
||||
return errors.New("passwords did not match, please try again")
|
||||
}
|
||||
|
||||
if err := user.SetPassword(newPassword); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("changed password for %s\n", txt.Quote(user.UserName))
|
||||
|
||||
conf.Shutdown()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// License: MIT Open Source
|
||||
// Copyright (c) Joe Linoff 2016
|
||||
// Go code to prompt for password using only standard packages by utilizing syscall.ForkExec() and syscall.Wait4().
|
||||
// Correctly resets terminal echo after ^C interrupts.
|
||||
//
|
||||
// techEcho() - turns terminal echo on or off.
|
||||
func termEcho(on bool) {
|
||||
// Common settings and variables for both stty calls.
|
||||
attrs := syscall.ProcAttr{
|
||||
Dir: "",
|
||||
Env: []string{},
|
||||
Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()},
|
||||
Sys: nil}
|
||||
var ws syscall.WaitStatus
|
||||
cmd := "echo"
|
||||
if on == false {
|
||||
cmd = "-echo"
|
||||
}
|
||||
|
||||
// Enable/disable echoing.
|
||||
pid, err := syscall.ForkExec(
|
||||
"/bin/stty",
|
||||
[]string{"stty", cmd},
|
||||
&attrs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Wait for the stty process to complete.
|
||||
_, err = syscall.Wait4(pid, &ws, 0, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// getPassword - Prompt for password.
|
||||
func getPassword(prompt string) string {
|
||||
fmt.Print(prompt)
|
||||
|
||||
// Catch a ^C interrupt.
|
||||
// Make sure that we reset term echo before exiting.
|
||||
signalChannel := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChannel, os.Interrupt)
|
||||
go func() {
|
||||
for _ = range signalChannel {
|
||||
fmt.Println("")
|
||||
termEcho(true)
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
// Echo is disabled, now grab the data.
|
||||
termEcho(false) // disable terminal echo
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
text, err := reader.ReadString('\n')
|
||||
termEcho(true) // always re-enable terminal echo
|
||||
fmt.Println("")
|
||||
if err != nil {
|
||||
// The terminal has been reset, go ahead and exit.
|
||||
fmt.Println("ERROR:", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
return strings.TrimSpace(text)
|
||||
}
|
|
@ -138,7 +138,7 @@ func FindPersonByUserName(userName string) *Person {
|
|||
if err := Db().Where("user_name = ?", userName).First(&result).Error; err == nil {
|
||||
return &result
|
||||
} else {
|
||||
log.Errorf("auth: user %s not found", txt.Quote(userName))
|
||||
log.Errorf("user %s not found", txt.Quote(userName))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ func FindPersonByUID(uid string) *Person {
|
|||
if err := Db().Where("person_uid = ?", uid).First(&result).Error; err == nil {
|
||||
return &result
|
||||
} else {
|
||||
log.Errorf("auth: user %s not found", txt.Quote(uid))
|
||||
log.Errorf("user %s not found", txt.Quote(uid))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +195,11 @@ func (m *Person) Guest() bool {
|
|||
// SetPassword sets a new password stored as hash.
|
||||
func (m *Person) SetPassword(password string) error {
|
||||
if !m.Registered() {
|
||||
return fmt.Errorf("auth: only registered users can change their password")
|
||||
return fmt.Errorf("only registered users can change their password")
|
||||
}
|
||||
|
||||
if len(password) < 6 {
|
||||
return fmt.Errorf("new password for %s must be at least 6 characters", txt.Quote(m.UserName))
|
||||
}
|
||||
|
||||
pw := NewPassword(m.PersonUID, password)
|
||||
|
@ -206,7 +210,7 @@ func (m *Person) SetPassword(password string) error {
|
|||
// InitPassword sets the initial user password stored as hash.
|
||||
func (m *Person) InitPassword(password string) {
|
||||
if !m.Registered() {
|
||||
log.Warn("auth: only registered users can change their password")
|
||||
log.Warn("only registered users can change their password")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -230,7 +234,7 @@ func (m *Person) InitPassword(password string) {
|
|||
// InvalidPassword returns true if the given password does not match the hash.
|
||||
func (m *Person) InvalidPassword(password string) bool {
|
||||
if !m.Registered() {
|
||||
log.Warn("auth: only registered users can change their password")
|
||||
log.Warn("only registered users can change their password")
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue