From 8d20c1b7d8ee9a6d10cfdf09c537402ac310b7bd Mon Sep 17 00:00:00 2001 From: Harvey Tindall Date: Sat, 9 Sep 2023 15:53:16 +0100 Subject: [PATCH] expand password reset documentation --- content/docs/faq.md | 4 +- content/docs/pwr/_index.md | 50 +++++++++ content/docs/pwr/pwr-pros-cons.html | 95 ++++++++++++++++++ .../remote-network.md} | 2 +- content/menu/index.md | 3 +- layouts/shortcodes/include-html.html | 2 + static/pwr-directory.png | Bin 0 -> 18628 bytes 7 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 content/docs/pwr/_index.md create mode 100644 content/docs/pwr/pwr-pros-cons.html rename content/docs/{password-resets.md => pwr/remote-network.md} (97%) create mode 100644 layouts/shortcodes/include-html.html create mode 100644 static/pwr-directory.png diff --git a/content/docs/faq.md b/content/docs/faq.md index 99413dd..f5d2a36 100644 --- a/content/docs/faq.md +++ b/content/docs/faq.md @@ -8,7 +8,7 @@ draft: false ([issue](https://github.com/hrfee/jellyfin-accounts/issues/12)) -* The best way to get around this (if you're using a reverse proxy) is to selectively not send the users real IP to jellyfin on the paths that are used for password resets. Read more and see an example [here]({{}}). +* The best way to get around this (if you're using a reverse proxy) is to selectively not send the users real IP to jellyfin on the paths that are used for password resets. Read more and see an example [here]({{}}). * Another method is to tell Jellyfin to treat all traffic as local. I don't recommend this as it stops you from using other features like remote bandwidth limiting. In Jellyfin, go to Dashboard > Networking (under Advanced), and set the 'LAN networks' setting to `0.0.0.0/0`. @@ -54,7 +54,7 @@ Make sure to check the ports you are using, as generally they correspond to the ## Does this need to be installed on the same host as Jellyfin? -Not necessarily. For invite functionality, an http connection is only necessary. However, password resets require jfa-go to be able to access Jellyfin's installation directory, so you'll need to use SMB or similar to mount it. +Not necessarily. For invite functionality, an http connection is only necessary. Password resets through the "User Page" Feature will also function, see [this note](/docs/pwr/#method-4-my-account-reset). However, password resets through the Jellyfin UI require jfa-go to be able to access its config directory, so you'll need to use SMB or similar to mount it. See [this page](/docs/pwr/#prerequisite-for-methods-1-3) for help finding the correct directory. ## Can i `go get` this repository? No, because the supporting files (CSS, email templates, etc.) need to be compiled and placed next to the executable before it will run, and `go get` will only compile the app itself. diff --git a/content/docs/pwr/_index.md b/content/docs/pwr/_index.md new file mode 100644 index 0000000..50eed57 --- /dev/null +++ b/content/docs/pwr/_index.md @@ -0,0 +1,50 @@ +--- +title: "Password Resets" +date: 2023-09-09T13:32:35+01:00 +draft: false +--- + +## Password Reset Methods +There are 4 main methods for facilitating password resets. They are ordered from (in my opinion, at least) worst to best, although your choice will depend on your situation.. They are described below: +1) **Through Jellyfin (PIN Reset)**: The user clicks "Forgot Password" on the Jellyfin login screen, and enters their username. Jellyfin generates a file with a PIN code. Jfa-go reads this file, and sends the PIN to any contact methods associated with the user (Email, Discord, Matrix or Telegram). The user then types this PIN when Jellyfin asks for it. +2) **Partially through Jellyfin (Link Reset)**: Similarly to above, the user clicks "Forgot Password" and enters their username. Jfa-go reads the file with the PIN, but instead sends the user a link that will automatically set their password to the PIN, as Jellyfin would if they typed it in. +3) **Partially through Jellyfin (Internal Reset)**: Same as above, but the link sent to the user takes them to a special jfa-go password reset page. +4) **Through Jfa-go (User Page/"My Account" Reset)**: The user visits the "My Account" page (`your-jfa-go.site/my/account`), and presses the "Forgot Password" button. They enter their Jellyfin username, or address/ID of a contact method (email address or discord/telegram/matrix username). A message with a link is sent, which links to the same password reset page described in method 2. + +## Pros/Cons + +{{< include-html "content/docs/pwr/pwr-pros-cons.html" >}} + +## Setting them up + +### Prerequisite for Methods 1-3 +jfa-go will need access to your Jellyfin config directory, as this is where it places the files containing PINs. + * General Advice: When initiating a password reset in Jellyfin, a message will pop up telling you the location the PIN file was created in. This is the easisest way to find the directory. However, this feature was [broken in older versions](https://github.com/jellyfin/jellyfin/issues/6093) and still is for some. + +![PWR Directory Screenshot](/pwr-directory.png) + + + * Docker: The directory you mounted to `/config` in the container, e.g. for `docker create ... -v /opt/jellyfin:/config`, the config directory would be `/opt/jellyfin`. + * If you're also running jfa-go in docker, make sure to mount it to `/jf` within the container; jfa-go should default to that path. + * Windows: The directory should be `C:\ProgramData\Jellyfin\Server` or similar. + * Ubuntu/Debian: Should be `/var/lib/jellyfin`, or one of it's sub-directories. initiate a Password Reset and look for a file beginning with `passwordreset` to confirm. + +### Method 1 (PIN Reset) + +* Enable Password Resets in settings, that's all. + +### Method 2 (Link Reset) + +* Enable Password Resets, and in the same section, enable *"Use reset link instead of PIN"*. + +### Method 3 (Internal Reset) + +* Enable both the settings for the above 2 methods, and also enable *"Set password through link"*. + +### Method 4 ("My Account" Reset) + +* Enable all of the settings listed above. +* Enable the *User Page* feature. +* Ensure *Use Jellyfin for Authentication* in *General* is enabled. + +* **Note**: Despite enabling the above features, jfa-go **does not need access** to the Jellyfin config directory if you only want this method to be used. You can point the directory to wherever, it doesn't matter. diff --git a/content/docs/pwr/pwr-pros-cons.html b/content/docs/pwr/pwr-pros-cons.html new file mode 100644 index 0000000..5c96cdc --- /dev/null +++ b/content/docs/pwr/pwr-pros-cons.html @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodsProsCons
PIN Reset +
    +
  • Initiated through Jellyfin
  • +
+
+
    +
  • + Can confuse user +
      +
    • Jellyfin doesn't tell you to check email/discord/telegram/matrix for a message with a PIN.
    • +
    +
  • +
  • + No way to enforce password requirements +
      +
    • User's password is set to the PIN, user must set their new password through Jellyfin.
    • +
    +
  • +
  • Ombi Password will not change (if enabled)
  • +
+
Link Reset +
    +
  • User doesn't have to keep Jellyfin's Password Reset page open
  • +
  • User doesn't have to type anything
  • +
  • Reminds user to change their password after it resets to the PIN code
  • +
  • Automatically changes password to PIN on Ombi
  • +
+
+
    +
  • Same as above
  • +
  • User will also have to manually change their Ombi password from the PIN
  • +
+
Internal Reset +
    +
  • + Enforces password requirements +
      +
    • Users are shown a page similar to the "Create Account" form
    • +
    +
  • +
  • New password is also applied to Ombi
  • +
+
+
    +
  • Can confuse user in the same way as the above
  • +
+
"My Account" Reset +
    +
  • Performed in the same place as other account management tasks
  • +
  • + Explains itself better than other methods +
      +
    • The page tells the user to check their inbox for a link +
    +
  • +
+
+
    +
  • + "My Account" page may not be familiar to user +
      +
    • For this feature to be used, users must know the "My Account" page exists
    • +
    • The page is already referenced on the signup form, but mentioning it on your Jellyfin instance or app portal might be a good idea.
    • +
    +
  • +
+
diff --git a/content/docs/password-resets.md b/content/docs/pwr/remote-network.md similarity index 97% rename from content/docs/password-resets.md rename to content/docs/pwr/remote-network.md index 988fc2d..69773b3 100644 --- a/content/docs/password-resets.md +++ b/content/docs/pwr/remote-network.md @@ -14,7 +14,7 @@ If you're using a reverse proxy, Jellyfin knows the real IP of a user through th ***Example NGINX config*** ```nginx - # add to your \`server {\` section + # add to your `server { ... }` block # rest of jellyfin config diff --git a/content/menu/index.md b/content/menu/index.md index 41445a6..1ed3fdf 100644 --- a/content/menu/index.md +++ b/content/menu/index.md @@ -17,7 +17,8 @@ headless = true - [Docker]({{< relref "/docs/build/docker" >}}) - [Development]({{< relref "/docs/dev" >}}) - [Web API Docs](https://api.jfa-go.com) -- [Password Resets outside local network]({{< relref "/docs/password-resets" >}}) +- [Password Resets]({{< relref "/docs/pwr/" >}}) + - [Password Resets outside local network]({{< relref "/docs/pwr/remote-network" >}}) - [Reverse Proxying]({{< relref "/docs/reverse-proxy" >}}) - [TLS Setup]({{< relref "/docs/tls" >}}) - [Translation]({{< relref "/docs/translation" >}}) diff --git a/layouts/shortcodes/include-html.html b/layouts/shortcodes/include-html.html new file mode 100644 index 0000000..fb8712b --- /dev/null +++ b/layouts/shortcodes/include-html.html @@ -0,0 +1,2 @@ +{{ $file := .Get 0 }} +{{ $file | readFile | safeHTML }} diff --git a/static/pwr-directory.png b/static/pwr-directory.png new file mode 100644 index 0000000000000000000000000000000000000000..f816f0a6ece46cbde4ac8c69fe974a0d0173d2cd GIT binary patch literal 18628 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 KnM|qc5B@JW62>_I literal 0 HcmV?d00001