1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-11-10 12:20:10 +00:00
jfa-go/pwreset.go
Harvey Tindall eb406ef951
Implement email template generation
Variables are surrounded by {}, and initial (default) templates are
generated on demand from the plaintext version of emails. The custom
emails are intended to only be used if the user actually changes them,
as they lose the features of the default ones, such as tables.
2021-02-19 21:38:20 +00:00

107 lines
3.0 KiB
Go

package main
import (
"encoding/json"
"os"
"strings"
"time"
"github.com/fsnotify/fsnotify"
)
func (app *appContext) StartPWR() {
app.info.Println("Starting password reset daemon")
path := app.config.Section("password_resets").Key("watch_directory").String()
if _, err := os.Stat(path); os.IsNotExist(err) {
app.err.Printf("Failed to start password reset daemon: Directory \"%s\" doesn't exist", path)
return
}
watcher, err := fsnotify.NewWatcher()
if err != nil {
app.err.Printf("Couldn't initialise password reset daemon")
return
}
defer watcher.Close()
done := make(chan bool)
go pwrMonitor(app, watcher)
err = watcher.Add(path)
if err != nil {
app.err.Printf("Failed to start password reset daemon: %s", err)
}
<-done
}
// PasswordReset represents a passwordreset-xyz.json file generated by Jellyfin.
type PasswordReset struct {
Pin string `json:"Pin"`
Username string `json:"UserName"`
Expiry time.Time `json:"ExpirationDate"`
}
func pwrMonitor(app *appContext, watcher *fsnotify.Watcher) {
if !emailEnabled {
return
}
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
if event.Op&fsnotify.Write == fsnotify.Write && strings.Contains(event.Name, "passwordreset") {
var pwr PasswordReset
data, err := os.ReadFile(event.Name)
if err != nil {
return
}
err = json.Unmarshal(data, &pwr)
if len(pwr.Pin) == 0 || err != nil {
return
}
app.info.Printf("New password reset for user \"%s\"", pwr.Username)
if currentTime := time.Now(); pwr.Expiry.After(currentTime) {
user, status, err := app.jf.UserByName(pwr.Username, false)
if !(status == 200 || status == 204) || err != nil {
app.err.Printf("Failed to get users from Jellyfin: Code %d", status)
app.debug.Printf("Error: %s", err)
return
}
app.storage.loadEmails()
var address string
uid := user.ID
if uid == "" {
app.err.Printf("Couldn't get user ID for user \"%s\"", pwr.Username)
return
}
addr, ok := app.storage.emails[uid]
if !ok || addr == nil {
app.err.Printf("Couldn't find email for user \"%s\". Make sure it's set", pwr.Username)
return
}
address = addr.(string)
msg, err := app.email.constructReset(pwr, app, false)
if err != nil {
app.err.Printf("Failed to construct password reset email for %s", pwr.Username)
app.debug.Printf("%s: Error: %s", pwr.Username, err)
} else if err := app.email.send(msg, address); err != nil {
app.err.Printf("Failed to send password reset email to \"%s\"", address)
app.debug.Printf("%s: Error: %s", pwr.Username, err)
} else {
app.info.Printf("Sent password reset email to \"%s\"", address)
}
} else {
app.err.Printf("Password reset for user \"%s\" has already expired (%s). Check your time settings.", pwr.Username, pwr.Expiry)
}
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
app.err.Printf("Password reset daemon: %s", err)
}
}
}