< Summary - Jellyfin

Information
Class: Jellyfin.Server.Implementations.Users.DefaultPasswordResetProvider
Assembly: Jellyfin.Server.Implementations
File(s): /srv/git/jellyfin/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs
Line coverage
66%
Covered lines: 4
Uncovered lines: 2
Coverable lines: 6
Total lines: 133
Line coverage: 66.6%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Name()100%210%
get_IsEnabled()100%210%

File(s)

/srv/git/jellyfin/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.IO;
 4using System.Security.Cryptography;
 5using System.Text.Json;
 6using System.Threading.Tasks;
 7using Jellyfin.Data.Entities;
 8using MediaBrowser.Common;
 9using MediaBrowser.Common.Extensions;
 10using MediaBrowser.Controller.Authentication;
 11using MediaBrowser.Controller.Configuration;
 12using MediaBrowser.Controller.Library;
 13using MediaBrowser.Model.IO;
 14using MediaBrowser.Model.Users;
 15
 16namespace Jellyfin.Server.Implementations.Users
 17{
 18    /// <summary>
 19    /// The default password reset provider.
 20    /// </summary>
 21    public class DefaultPasswordResetProvider : IPasswordResetProvider
 22    {
 23        private const string BaseResetFileName = "passwordreset";
 24
 25        private readonly IApplicationHost _appHost;
 26
 27        private readonly string _passwordResetFileBase;
 28        private readonly string _passwordResetFileBaseDir;
 29
 30        /// <summary>
 31        /// Initializes a new instance of the <see cref="DefaultPasswordResetProvider"/> class.
 32        /// </summary>
 33        /// <param name="configurationManager">The configuration manager.</param>
 34        /// <param name="appHost">The application host.</param>
 35        public DefaultPasswordResetProvider(IServerConfigurationManager configurationManager, IApplicationHost appHost)
 36        {
 2237            _passwordResetFileBaseDir = configurationManager.ApplicationPaths.ProgramDataPath;
 2238            _passwordResetFileBase = Path.Combine(_passwordResetFileBaseDir, BaseResetFileName);
 2239            _appHost = appHost;
 40            // TODO: Remove the circular dependency on UserManager
 2241        }
 42
 43        /// <inheritdoc />
 044        public string Name => "Default Password Reset Provider";
 45
 46        /// <inheritdoc />
 047        public bool IsEnabled => true;
 48
 49        /// <inheritdoc />
 50        public async Task<PinRedeemResult> RedeemPasswordResetPin(string pin)
 51        {
 52            var userManager = _appHost.Resolve<IUserManager>();
 53            var usersReset = new List<string>();
 54            foreach (var resetFile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{BaseResetFileName}*"))
 55            {
 56                SerializablePasswordReset spr;
 57                var str = AsyncFile.OpenRead(resetFile);
 58                await using (str.ConfigureAwait(false))
 59                {
 60                    spr = await JsonSerializer.DeserializeAsync<SerializablePasswordReset>(str).ConfigureAwait(false)
 61                        ?? throw new ResourceNotFoundException($"Provided path ({resetFile}) is not valid.");
 62                }
 63
 64                if (spr.ExpirationDate < DateTime.UtcNow)
 65                {
 66                    File.Delete(resetFile);
 67                }
 68                else if (string.Equals(
 69                    spr.Pin.Replace("-", string.Empty, StringComparison.Ordinal),
 70                    pin.Replace("-", string.Empty, StringComparison.Ordinal),
 71                    StringComparison.Ordinal))
 72                {
 73                    var resetUser = userManager.GetUserByName(spr.UserName)
 74                        ?? throw new ResourceNotFoundException($"User with a username of {spr.UserName} not found");
 75
 76                    await userManager.ChangePassword(resetUser, pin).ConfigureAwait(false);
 77                    usersReset.Add(resetUser.Username);
 78                    File.Delete(resetFile);
 79                }
 80            }
 81
 82            if (usersReset.Count < 1)
 83            {
 84                throw new ResourceNotFoundException($"No Users found with a password reset request matching pin {pin}");
 85            }
 86
 87            return new PinRedeemResult
 88            {
 89                Success = true,
 90                UsersReset = usersReset.ToArray()
 91            };
 92        }
 93
 94        /// <inheritdoc />
 95        public async Task<ForgotPasswordResult> StartForgotPasswordProcess(User user, bool isInNetwork)
 96        {
 97            byte[] bytes = new byte[4];
 98            RandomNumberGenerator.Fill(bytes);
 99            string pin = BitConverter.ToString(bytes);
 100
 101            DateTime expireTime = DateTime.UtcNow.AddMinutes(30);
 102            string filePath = _passwordResetFileBase + user.Id + ".json";
 103            SerializablePasswordReset spr = new SerializablePasswordReset
 104            {
 105                ExpirationDate = expireTime,
 106                Pin = pin,
 107                PinFile = filePath,
 108                UserName = user.Username
 109            };
 110
 111            FileStream fileStream = AsyncFile.OpenWrite(filePath);
 112            await using (fileStream.ConfigureAwait(false))
 113            {
 114                await JsonSerializer.SerializeAsync(fileStream, spr).ConfigureAwait(false);
 115            }
 116
 117            return new ForgotPasswordResult
 118            {
 119                Action = ForgotPasswordAction.PinCode,
 120                PinExpirationDate = expireTime,
 121                PinFile = filePath
 122            };
 123        }
 124
 125#nullable disable
 126        private class SerializablePasswordReset : PasswordPinCreationResult
 127        {
 128            public string Pin { get; set; }
 129
 130            public string UserName { get; set; }
 131        }
 132    }
 133}