Refactor: standardize namespace and using directive style
Refactored all C# test files to use explicit namespace declarations and moved all using directives inside the namespace block for consistency. Updated assembly info and cache files to reflect the new build. Adjusted MvcTestingAppManifest.json to use fully qualified assembly names. No functional changes; all updates are related to code style, organization, and project metadata.
This commit is contained in:
@@ -2,26 +2,24 @@
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace MediaBrowser.Model.Cryptography
|
||||
{
|
||||
/// <summary>
|
||||
/// Class containing global constants for Jellyfin Cryptography.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// The default length for new salts.
|
||||
/// </summary>
|
||||
public const int DefaultSaltLength = 128 / 8;
|
||||
namespace MediaBrowser.Model.Cryptography;
|
||||
/// <summary>
|
||||
/// Class containing global constants for Jellyfin Cryptography.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// The default length for new salts.
|
||||
/// </summary>
|
||||
public const int DefaultSaltLength = 128 / 8;
|
||||
|
||||
/// <summary>
|
||||
/// The default output length.
|
||||
/// </summary>
|
||||
public const int DefaultOutputLength = 512 / 8;
|
||||
/// <summary>
|
||||
/// The default output length.
|
||||
/// </summary>
|
||||
public const int DefaultOutputLength = 512 / 8;
|
||||
|
||||
/// <summary>
|
||||
/// The default amount of iterations for hashing passwords.
|
||||
/// </summary>
|
||||
public const int DefaultIterations = 210000;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The default amount of iterations for hashing passwords.
|
||||
/// </summary>
|
||||
public const int DefaultIterations = 210000;
|
||||
}
|
||||
|
||||
@@ -4,25 +4,23 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using global::System;
|
||||
|
||||
namespace MediaBrowser.Model.Cryptography
|
||||
{
|
||||
public interface ICryptoProvider
|
||||
{
|
||||
string DefaultHashMethod { get; }
|
||||
namespace MediaBrowser.Model.Cryptography;
|
||||
public interface ICryptoProvider
|
||||
{
|
||||
string DefaultHashMethod { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="PasswordHash" /> instance.
|
||||
/// </summary>
|
||||
/// <param name="password">The password that will be hashed.</param>
|
||||
/// <returns>A <see cref="PasswordHash" /> instance with the hash method, hash, salt and number of iterations.</returns>
|
||||
PasswordHash CreatePasswordHash(ReadOnlySpan<char> password);
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="PasswordHash" /> instance.
|
||||
/// </summary>
|
||||
/// <param name="password">The password that will be hashed.</param>
|
||||
/// <returns>A <see cref="PasswordHash" /> instance with the hash method, hash, salt and number of iterations.</returns>
|
||||
PasswordHash CreatePasswordHash(ReadOnlySpan<char> password);
|
||||
|
||||
bool Verify(PasswordHash hash, ReadOnlySpan<char> password);
|
||||
bool Verify(PasswordHash hash, ReadOnlySpan<char> password);
|
||||
|
||||
byte[] GenerateSalt();
|
||||
byte[] GenerateSalt();
|
||||
|
||||
byte[] GenerateSalt(int length);
|
||||
}
|
||||
}
|
||||
byte[] GenerateSalt(int length);
|
||||
}
|
||||
|
||||
@@ -4,213 +4,212 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using global::System;
|
||||
using global::System.Collections.Generic;
|
||||
using global::System.Text;
|
||||
|
||||
namespace MediaBrowser.Model.Cryptography
|
||||
{
|
||||
// Defined from this hash storage spec
|
||||
// https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md
|
||||
// $<id>[$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]]
|
||||
// with one slight amendment to ease the transition, we're writing out the bytes in hex
|
||||
// rather than making them a BASE64 string with stripped padding
|
||||
public class PasswordHash
|
||||
{
|
||||
private readonly Dictionary<string, string> _parameters;
|
||||
private readonly byte[] _salt;
|
||||
private readonly byte[] _hash;
|
||||
namespace MediaBrowser.Model.Cryptography;
|
||||
|
||||
public PasswordHash(string id, byte[] hash)
|
||||
: this(id, hash, Array.Empty<byte>())
|
||||
{
|
||||
}
|
||||
// Defined from this hash storage spec
|
||||
// https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md
|
||||
// $<id>[$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]]
|
||||
// with one slight amendment to ease the transition, we're writing out the bytes in hex
|
||||
// rather than making them a BASE64 string with stripped padding
|
||||
public class PasswordHash
|
||||
{
|
||||
private readonly Dictionary<string, string> _parameters;
|
||||
private readonly byte[] _salt;
|
||||
private readonly byte[] _hash;
|
||||
|
||||
public PasswordHash(string id, byte[] hash, byte[] salt)
|
||||
: this(id, hash, salt, new Dictionary<string, string>())
|
||||
{
|
||||
}
|
||||
public PasswordHash(string id, byte[] hash)
|
||||
: this(id, hash, Array.Empty<byte>())
|
||||
{
|
||||
}
|
||||
|
||||
public PasswordHash(string id, byte[] hash, byte[] salt, Dictionary<string, string> parameters)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrEmpty(id);
|
||||
public PasswordHash(string id, byte[] hash, byte[] salt)
|
||||
: this(id, hash, salt, new Dictionary<string, string>())
|
||||
{
|
||||
}
|
||||
|
||||
Id = id;
|
||||
_hash = hash;
|
||||
_salt = salt;
|
||||
_parameters = parameters;
|
||||
}
|
||||
public PasswordHash(string id, byte[] hash, byte[] salt, Dictionary<string, string> parameters)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrEmpty(id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the symbolic name for the function used.
|
||||
/// </summary>
|
||||
/// <value>Returns the symbolic name for the function used.</value>
|
||||
public string Id { get; }
|
||||
Id = id;
|
||||
_hash = hash;
|
||||
_salt = salt;
|
||||
_parameters = parameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the additional parameters used by the hash function.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, string> Parameters => _parameters;
|
||||
/// <summary>
|
||||
/// Gets the symbolic name for the function used.
|
||||
/// </summary>
|
||||
/// <value>Returns the symbolic name for the function used.</value>
|
||||
public string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the salt used for hashing the password.
|
||||
/// </summary>
|
||||
/// <value>Returns the salt used for hashing the password.</value>
|
||||
public ReadOnlySpan<byte> Salt => _salt;
|
||||
/// <summary>
|
||||
/// Gets the additional parameters used by the hash function.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, string> Parameters => _parameters;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hashed password.
|
||||
/// </summary>
|
||||
/// <value>Return the hashed password.</value>
|
||||
public ReadOnlySpan<byte> Hash => _hash;
|
||||
/// <summary>
|
||||
/// Gets the salt used for hashing the password.
|
||||
/// </summary>
|
||||
/// <value>Returns the salt used for hashing the password.</value>
|
||||
public ReadOnlySpan<byte> Salt => _salt;
|
||||
|
||||
public static PasswordHash Parse(ReadOnlySpan<char> hashString)
|
||||
{
|
||||
if (hashString.IsEmpty)
|
||||
{
|
||||
throw new ArgumentException("String can't be empty", nameof(hashString));
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the hashed password.
|
||||
/// </summary>
|
||||
/// <value>Return the hashed password.</value>
|
||||
public ReadOnlySpan<byte> Hash => _hash;
|
||||
|
||||
if (hashString[0] != '$')
|
||||
{
|
||||
throw new FormatException("Hash string must start with a $");
|
||||
}
|
||||
public static PasswordHash Parse(ReadOnlySpan<char> hashString)
|
||||
{
|
||||
if (hashString.IsEmpty)
|
||||
{
|
||||
throw new ArgumentException("String can't be empty", nameof(hashString));
|
||||
}
|
||||
|
||||
// Ignore first $
|
||||
hashString = hashString[1..];
|
||||
if (hashString[0] != '$')
|
||||
{
|
||||
throw new FormatException("Hash string must start with a $");
|
||||
}
|
||||
|
||||
int nextSegment = hashString.IndexOf('$');
|
||||
if (hashString.IsEmpty || nextSegment == 0)
|
||||
{
|
||||
throw new FormatException("Hash string must contain a valid id");
|
||||
}
|
||||
// Ignore first $
|
||||
hashString = hashString[1..];
|
||||
|
||||
if (nextSegment == -1)
|
||||
{
|
||||
return new PasswordHash(hashString.ToString(), Array.Empty<byte>());
|
||||
}
|
||||
int nextSegment = hashString.IndexOf('$');
|
||||
if (hashString.IsEmpty || nextSegment == 0)
|
||||
{
|
||||
throw new FormatException("Hash string must contain a valid id");
|
||||
}
|
||||
|
||||
ReadOnlySpan<char> id = hashString[..nextSegment];
|
||||
hashString = hashString[(nextSegment + 1)..];
|
||||
Dictionary<string, string>? parameters = null;
|
||||
if (nextSegment == -1)
|
||||
{
|
||||
return new PasswordHash(hashString.ToString(), Array.Empty<byte>());
|
||||
}
|
||||
|
||||
nextSegment = hashString.IndexOf('$');
|
||||
ReadOnlySpan<char> id = hashString[..nextSegment];
|
||||
hashString = hashString[(nextSegment + 1)..];
|
||||
Dictionary<string, string>? parameters = null;
|
||||
|
||||
// Optional parameters
|
||||
ReadOnlySpan<char> parametersSpan = nextSegment == -1 ? hashString : hashString[..nextSegment];
|
||||
if (parametersSpan.Contains('='))
|
||||
{
|
||||
while (!parametersSpan.IsEmpty)
|
||||
{
|
||||
ReadOnlySpan<char> parameter;
|
||||
int index = parametersSpan.IndexOf(',');
|
||||
if (index == -1)
|
||||
{
|
||||
parameter = parametersSpan;
|
||||
parametersSpan = ReadOnlySpan<char>.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
parameter = parametersSpan[..index];
|
||||
parametersSpan = parametersSpan[(index + 1)..];
|
||||
}
|
||||
nextSegment = hashString.IndexOf('$');
|
||||
|
||||
int splitIndex = parameter.IndexOf('=');
|
||||
if (splitIndex == -1 || splitIndex == 0 || splitIndex == parameter.Length - 1)
|
||||
{
|
||||
throw new FormatException("Malformed parameter in password hash string");
|
||||
}
|
||||
// Optional parameters
|
||||
ReadOnlySpan<char> parametersSpan = nextSegment == -1 ? hashString : hashString[..nextSegment];
|
||||
if (parametersSpan.Contains('='))
|
||||
{
|
||||
while (!parametersSpan.IsEmpty)
|
||||
{
|
||||
ReadOnlySpan<char> parameter;
|
||||
int index = parametersSpan.IndexOf(',');
|
||||
if (index == -1)
|
||||
{
|
||||
parameter = parametersSpan;
|
||||
parametersSpan = ReadOnlySpan<char>.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
parameter = parametersSpan[..index];
|
||||
parametersSpan = parametersSpan[(index + 1)..];
|
||||
}
|
||||
|
||||
(parameters ??= new Dictionary<string, string>()).Add(
|
||||
parameter[..splitIndex].ToString(),
|
||||
parameter[(splitIndex + 1)..].ToString());
|
||||
}
|
||||
int splitIndex = parameter.IndexOf('=');
|
||||
if (splitIndex == -1 || splitIndex == 0 || splitIndex == parameter.Length - 1)
|
||||
{
|
||||
throw new FormatException("Malformed parameter in password hash string");
|
||||
}
|
||||
|
||||
if (nextSegment == -1)
|
||||
{
|
||||
// parameters can't be null here
|
||||
return new PasswordHash(id.ToString(), Array.Empty<byte>(), Array.Empty<byte>(), parameters!);
|
||||
}
|
||||
(parameters ??= new Dictionary<string, string>()).Add(
|
||||
parameter[..splitIndex].ToString(),
|
||||
parameter[(splitIndex + 1)..].ToString());
|
||||
}
|
||||
|
||||
hashString = hashString[(nextSegment + 1)..];
|
||||
nextSegment = hashString.IndexOf('$');
|
||||
}
|
||||
if (nextSegment == -1)
|
||||
{
|
||||
// parameters can't be null here
|
||||
return new PasswordHash(id.ToString(), Array.Empty<byte>(), Array.Empty<byte>(), parameters!);
|
||||
}
|
||||
|
||||
if (nextSegment == 0)
|
||||
{
|
||||
throw new FormatException("Hash string contains an empty segment");
|
||||
}
|
||||
hashString = hashString[(nextSegment + 1)..];
|
||||
nextSegment = hashString.IndexOf('$');
|
||||
}
|
||||
|
||||
byte[] hash;
|
||||
byte[] salt;
|
||||
if (nextSegment == 0)
|
||||
{
|
||||
throw new FormatException("Hash string contains an empty segment");
|
||||
}
|
||||
|
||||
if (nextSegment == -1)
|
||||
{
|
||||
salt = Array.Empty<byte>();
|
||||
hash = Convert.FromHexString(hashString);
|
||||
}
|
||||
else
|
||||
{
|
||||
salt = Convert.FromHexString(hashString[..nextSegment]);
|
||||
hashString = hashString[(nextSegment + 1)..];
|
||||
nextSegment = hashString.IndexOf('$');
|
||||
if (nextSegment != -1)
|
||||
{
|
||||
throw new FormatException("Hash string contains too many segments");
|
||||
}
|
||||
byte[] hash;
|
||||
byte[] salt;
|
||||
|
||||
if (hashString.IsEmpty)
|
||||
{
|
||||
throw new FormatException("Hash segment is empty");
|
||||
}
|
||||
if (nextSegment == -1)
|
||||
{
|
||||
salt = Array.Empty<byte>();
|
||||
hash = Convert.FromHexString(hashString);
|
||||
}
|
||||
else
|
||||
{
|
||||
salt = Convert.FromHexString(hashString[..nextSegment]);
|
||||
hashString = hashString[(nextSegment + 1)..];
|
||||
nextSegment = hashString.IndexOf('$');
|
||||
if (nextSegment != -1)
|
||||
{
|
||||
throw new FormatException("Hash string contains too many segments");
|
||||
}
|
||||
|
||||
hash = Convert.FromHexString(hashString);
|
||||
}
|
||||
if (hashString.IsEmpty)
|
||||
{
|
||||
throw new FormatException("Hash segment is empty");
|
||||
}
|
||||
|
||||
return new PasswordHash(id.ToString(), hash, salt, parameters ?? new Dictionary<string, string>());
|
||||
}
|
||||
hash = Convert.FromHexString(hashString);
|
||||
}
|
||||
|
||||
private void SerializeParameters(StringBuilder stringBuilder)
|
||||
{
|
||||
if (_parameters.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return new PasswordHash(id.ToString(), hash, salt, parameters ?? new Dictionary<string, string>());
|
||||
}
|
||||
|
||||
stringBuilder.Append('$');
|
||||
foreach (var pair in _parameters)
|
||||
{
|
||||
stringBuilder.Append(pair.Key)
|
||||
.Append('=')
|
||||
.Append(pair.Value)
|
||||
.Append(',');
|
||||
}
|
||||
private void SerializeParameters(StringBuilder stringBuilder)
|
||||
{
|
||||
if (_parameters.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove last ','
|
||||
stringBuilder.Length -= 1;
|
||||
}
|
||||
stringBuilder.Append('$');
|
||||
foreach (var pair in _parameters)
|
||||
{
|
||||
stringBuilder.Append(pair.Key)
|
||||
.Append('=')
|
||||
.Append(pair.Value)
|
||||
.Append(',');
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var str = new StringBuilder()
|
||||
.Append('$')
|
||||
.Append(Id);
|
||||
SerializeParameters(str);
|
||||
// Remove last ','
|
||||
stringBuilder.Length -= 1;
|
||||
}
|
||||
|
||||
if (_salt.Length != 0)
|
||||
{
|
||||
str.Append('$')
|
||||
.Append(Convert.ToHexString(_salt));
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var str = new StringBuilder()
|
||||
.Append('$')
|
||||
.Append(Id);
|
||||
SerializeParameters(str);
|
||||
|
||||
if (_hash.Length != 0)
|
||||
{
|
||||
str.Append('$')
|
||||
.Append(Convert.ToHexString(_hash));
|
||||
}
|
||||
if (_salt.Length != 0)
|
||||
{
|
||||
str.Append('$')
|
||||
.Append(Convert.ToHexString(_salt));
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_hash.Length != 0)
|
||||
{
|
||||
str.Append('$')
|
||||
.Append(Convert.ToHexString(_hash));
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user