2020-07-01 12:34:53 +02:00
|
|
|
package commands
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/signal"
|
|
|
|
"strings"
|
|
|
|
"syscall"
|
|
|
|
|
2021-09-22 19:33:41 +02:00
|
|
|
"github.com/urfave/cli"
|
|
|
|
|
2020-07-01 12:34:53 +02:00
|
|
|
"github.com/photoprism/photoprism/internal/config"
|
|
|
|
"github.com/photoprism/photoprism/internal/entity"
|
|
|
|
"github.com/photoprism/photoprism/pkg/txt"
|
|
|
|
)
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
2020-10-08 08:52:03 +02:00
|
|
|
_, cancel := context.WithCancel(context.Background())
|
2020-07-01 12:34:53 +02:00
|
|
|
defer cancel()
|
2020-10-08 08:52:03 +02:00
|
|
|
|
|
|
|
if err := conf.Init(); err != nil {
|
2020-07-01 12:34:53 +02:00
|
|
|
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)
|
|
|
|
}
|