New: Don't return API Keys and Passwords via the API

(cherry picked from commit 570be882154e73f8ad1de5b16b957bcb964697fd)
(cherry picked from commit 508a15e09ac1b08a90837d371353cdf11cd9ee3c)
pull/4220/head
Mark McDowall 2 years ago committed by Qstick
parent f040835321
commit aa65dadc49

@ -65,7 +65,10 @@ namespace Lidarr.Api.V1.CustomFormats
var type = matchingSpec.GetType();
var spec = (ICustomFormatSpecification)SchemaBuilder.ReadFromSchema(resource.Fields, type);
// Finding the exact current specification isn't possible given the dynamic nature of them and the possibility that multiple
// of the same type exist within the same format. Passing in null is safe as long as there never exists a specification that
// relies on additional privacy.
var spec = (ICustomFormatSpecification)SchemaBuilder.ReadFromSchema(resource.Fields, type, null);
spec.Name = resource.Name;
spec.Negate = resource.Negate;
spec.Required = resource.Required;

@ -32,14 +32,14 @@ namespace Lidarr.Api.V1.DownloadClient
return resource;
}
public override DownloadClientDefinition ToModel(DownloadClientResource resource)
public override DownloadClientDefinition ToModel(DownloadClientResource resource, DownloadClientDefinition existingDefinition)
{
if (resource == null)
{
return null;
}
var definition = base.ToModel(resource);
var definition = base.ToModel(resource, existingDefinition);
definition.Enable = resource.Enable;
definition.Protocol = resource.Protocol;

@ -45,14 +45,14 @@ namespace Lidarr.Api.V1.ImportLists
return resource;
}
public override ImportListDefinition ToModel(ImportListResource resource)
public override ImportListDefinition ToModel(ImportListResource resource, ImportListDefinition existingDefinition)
{
if (resource == null)
{
return null;
}
var definition = base.ToModel(resource);
var definition = base.ToModel(resource, existingDefinition);
definition.EnableAutomaticAdd = resource.EnableAutomaticAdd;
definition.ShouldMonitor = resource.ShouldMonitor;

@ -37,14 +37,14 @@ namespace Lidarr.Api.V1.Indexers
return resource;
}
public override IndexerDefinition ToModel(IndexerResource resource)
public override IndexerDefinition ToModel(IndexerResource resource, IndexerDefinition existingDefinition)
{
if (resource == null)
{
return null;
}
var definition = base.ToModel(resource);
var definition = base.ToModel(resource, existingDefinition);
definition.EnableRss = resource.EnableRss;
definition.EnableAutomaticSearch = resource.EnableAutomaticSearch;

@ -23,14 +23,14 @@ namespace Lidarr.Api.V1.Metadata
return resource;
}
public override MetadataDefinition ToModel(MetadataResource resource)
public override MetadataDefinition ToModel(MetadataResource resource, MetadataDefinition existingDefinition)
{
if (resource == null)
{
return null;
}
var definition = base.ToModel(resource);
var definition = base.ToModel(resource, existingDefinition);
definition.Enable = resource.Enable;

@ -73,14 +73,14 @@ namespace Lidarr.Api.V1.Notifications
return resource;
}
public override NotificationDefinition ToModel(NotificationResource resource)
public override NotificationDefinition ToModel(NotificationResource resource, NotificationDefinition existingDefinition)
{
if (resource == null)
{
return default(NotificationDefinition);
}
var definition = base.ToModel(resource);
var definition = base.ToModel(resource, existingDefinition);
definition.OnGrab = resource.OnGrab;
definition.OnReleaseImport = resource.OnReleaseImport;

@ -143,7 +143,8 @@ namespace Lidarr.Api.V1
private TProviderDefinition GetDefinition(TProviderResource providerResource, bool validate, bool includeWarnings, bool forceValidate)
{
var definition = _resourceMapper.ToModel(providerResource);
var existingDefinition = providerResource.Id > 0 ? _providerFactory.Find(providerResource.Id) : null;
var definition = _resourceMapper.ToModel(providerResource, existingDefinition);
if (validate && (definition.Enable || forceValidate))
{

@ -44,7 +44,7 @@ namespace Lidarr.Api.V1
};
}
public virtual TProviderDefinition ToModel(TProviderResource resource)
public virtual TProviderDefinition ToModel(TProviderResource resource, TProviderDefinition existingDefinition)
{
if (resource == null)
{
@ -64,7 +64,7 @@ namespace Lidarr.Api.V1
};
var configContract = ReflectionExtensions.CoreAssembly.FindTypeByName(definition.ConfigContract);
definition.Settings = (IProviderConfig)SchemaBuilder.ReadFromSchema(resource.Fields, configContract);
definition.Settings = (IProviderConfig)SchemaBuilder.ReadFromSchema(resource.Fields, configContract, existingDefinition?.Settings);
return definition;
}

@ -1,4 +1,5 @@
using System.Collections.Generic;
using NzbDrone.Core.Annotations;
namespace Lidarr.Http.ClientSchema
{
@ -18,6 +19,7 @@ namespace Lidarr.Http.ClientSchema
public string SelectOptionsProviderAction { get; set; }
public string Section { get; set; }
public string Hidden { get; set; }
public PrivacyLevel Privacy { get; set; }
public string Placeholder { get; set; }
public bool IsFloat { get; set; }

@ -13,6 +13,7 @@ namespace Lidarr.Http.ClientSchema
{
public static class SchemaBuilder
{
private const string PRIVATE_VALUE = "********";
private static Dictionary<Type, FieldMapping[]> _mappings = new Dictionary<Type, FieldMapping[]>();
public static List<Field> ToSchema(object model)
@ -26,7 +27,15 @@ namespace Lidarr.Http.ClientSchema
foreach (var mapping in mappings)
{
var field = mapping.Field.Clone();
field.Value = mapping.GetterFunc(model);
if (field.Privacy == PrivacyLevel.ApiKey || field.Privacy == PrivacyLevel.Password)
{
field.Value = PRIVATE_VALUE;
}
else
{
field.Value = mapping.GetterFunc(model);
}
result.Add(field);
}
@ -34,7 +43,7 @@ namespace Lidarr.Http.ClientSchema
return result.OrderBy(r => r.Order).ToList();
}
public static object ReadFromSchema(List<Field> fields, Type targetType)
public static object ReadFromSchema(List<Field> fields, Type targetType, object model)
{
Ensure.That(targetType, () => targetType).IsNotNull();
@ -48,18 +57,25 @@ namespace Lidarr.Http.ClientSchema
if (field != null)
{
mapping.SetterFunc(target, field.Value);
// Use the Privacy property from the mapping's field as Privacy may not be set in the API request (nor is it required)
if ((mapping.Field.Privacy == PrivacyLevel.ApiKey || mapping.Field.Privacy == PrivacyLevel.Password) &&
(field.Value?.ToString()?.Equals(PRIVATE_VALUE) ?? false) &&
model != null)
{
var existingValue = mapping.GetterFunc(model);
mapping.SetterFunc(target, existingValue);
}
else
{
mapping.SetterFunc(target, field.Value);
}
}
}
return target;
}
public static T ReadFromSchema<T>(List<Field> fields)
{
return (T)ReadFromSchema(fields, typeof(T));
}
// Ideally this function should begin a System.Linq.Expression expression tree since it's faster.
// But it's probably not needed till performance issues pop up.
public static FieldMapping[] GetFieldMappings(Type type)
@ -104,6 +120,7 @@ namespace Lidarr.Http.ClientSchema
Advanced = fieldAttribute.Advanced,
Type = fieldAttribute.Type.ToString().FirstCharToLower(),
Section = fieldAttribute.Section,
Privacy = fieldAttribute.Privacy,
Placeholder = fieldAttribute.Placeholder
};
@ -136,7 +153,7 @@ namespace Lidarr.Http.ClientSchema
Field = field,
PropertyType = propertyInfo.PropertyType,
GetterFunc = t => propertyInfo.GetValue(targetSelector(t), null),
SetterFunc = (t, v) => propertyInfo.SetValue(targetSelector(t), valueConverter(v), null)
SetterFunc = (t, v) => propertyInfo.SetValue(targetSelector(t), v?.GetType() == propertyInfo.PropertyType ? v : valueConverter(v), null)
});
}
else

Loading…
Cancel
Save