aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Dlna/ContentDirectory/ControlHandler.cs2
-rw-r--r--Emby.Dlna/Didl/DidlBuilder.cs30
-rw-r--r--Emby.Dlna/PlayTo/Device.cs30
-rw-r--r--Emby.Dlna/PlayTo/PlayToController.cs7
-rw-r--r--Emby.Dlna/Profiles/LgTvProfile.cs6
-rw-r--r--Emby.Dlna/Profiles/Xml/LG Smart TV.xml6
-rw-r--r--Emby.Drawing.ImageMagick/ImageMagickEncoder.cs9
-rw-r--r--Emby.Drawing.Skia/SkiaEncoder.cs6
-rw-r--r--Emby.Drawing/ImageProcessor.cs161
-rw-r--r--Emby.Photos/PhotoProvider.cs189
-rw-r--r--Emby.Server.Implementations/Activity/ActivityRepository.cs21
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs86
-rw-r--r--Emby.Server.Implementations/Archiving/ZipClient.cs17
-rw-r--r--Emby.Server.Implementations/Cryptography/ASN1.cs340
-rw-r--r--Emby.Server.Implementations/Cryptography/ASN1Convert.cs207
-rw-r--r--Emby.Server.Implementations/Cryptography/BitConverterLE.cs239
-rw-r--r--Emby.Server.Implementations/Cryptography/CertificateGenerator.cs109
-rw-r--r--Emby.Server.Implementations/Cryptography/CryptoConvert.cs745
-rw-r--r--Emby.Server.Implementations/Cryptography/PKCS1.cs491
-rw-r--r--Emby.Server.Implementations/Cryptography/PKCS12.cs1934
-rw-r--r--Emby.Server.Implementations/Cryptography/PKCS7.cs1012
-rw-r--r--Emby.Server.Implementations/Cryptography/PKCS8.cs495
-rw-r--r--Emby.Server.Implementations/Cryptography/PfxGenerator.cs75
-rw-r--r--Emby.Server.Implementations/Cryptography/X501Name.cs393
-rw-r--r--Emby.Server.Implementations/Cryptography/X509Builder.cs153
-rw-r--r--Emby.Server.Implementations/Cryptography/X509Certificate.cs563
-rw-r--r--Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs245
-rw-r--r--Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs201
-rw-r--r--Emby.Server.Implementations/Cryptography/X509Extension.cs208
-rw-r--r--Emby.Server.Implementations/Cryptography/X509Extensions.cs195
-rw-r--r--Emby.Server.Implementations/Cryptography/X520Attributes.cs346
-rw-r--r--Emby.Server.Implementations/Data/BaseSqliteRepository.cs93
-rw-r--r--Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs22
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs8
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs21
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj25
-rw-r--r--Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs2
-rw-r--r--Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs4
-rw-r--r--Emby.Server.Implementations/EntryPoints/UsageReporter.cs10
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs43
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpResultFactory.cs72
-rw-r--r--Emby.Server.Implementations/IO/LibraryMonitor.cs8
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs61
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs4
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs12
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs54
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs7
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs11
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs153
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs4
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs81
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs45
-rw-r--r--Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs2
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs14
-rw-r--r--Emby.Server.Implementations/Social/SharingRepository.cs24
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs36
-rw-r--r--Emby.Server.Implementations/packages.config2
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs52
-rw-r--r--MediaBrowser.Common/Updates/GithubUpdater.cs24
-rw-r--r--MediaBrowser.Controller/Channels/Channel.cs8
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/ImageHelper.cs5
-rw-r--r--MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs2
-rw-r--r--MediaBrowser.Controller/Entities/BasePluginFolder.cs8
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs8
-rw-r--r--MediaBrowser.Controller/Entities/GameGenre.cs5
-rw-r--r--MediaBrowser.Controller/Entities/GameSystem.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs5
-rw-r--r--MediaBrowser.Controller/Entities/Photo.cs29
-rw-r--r--MediaBrowser.Controller/Entities/PhotoAlbum.cs5
-rw-r--r--MediaBrowser.Controller/Entities/User.cs5
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs8
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs15
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Year.cs8
-rw-r--r--MediaBrowser.Controller/IO/StreamHelper.cs5
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/ITunerHost.cs15
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveStream.cs87
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj1
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs91
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs159
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs46
-rw-r--r--MediaBrowser.Controller/TV/ITVSeriesManager.cs2
-rw-r--r--MediaBrowser.Model/Configuration/EncodingOptions.cs3
-rw-r--r--MediaBrowser.Model/Configuration/LibraryOptions.cs3
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs10
-rw-r--r--MediaBrowser.Model/Dlna/CodecProfile.cs21
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs193
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs210
-rw-r--r--MediaBrowser.Model/IO/IZipClient.cs2
-rw-r--r--MediaBrowser.Providers/Manager/ItemImageProvider.cs4
-rw-r--r--MediaBrowser.Providers/TV/DummySeasonProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/SeasonMetadataService.cs8
-rw-r--r--MediaBrowser.Server.Mono/ImageEncoderHelper.cs1
-rw-r--r--MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj5
-rw-r--r--MediaBrowser.Server.Mono/MonoAppHost.cs3
-rw-r--r--MediaBrowser.Server.Mono/Program.cs2
-rw-r--r--MediaBrowser.Server.Mono/packages.config2
-rw-r--r--MediaBrowser.ServerApplication/ImageEncoderHelper.cs1
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs2
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj5
-rw-r--r--MediaBrowser.ServerApplication/WindowsAppHost.cs1
-rw-r--r--MediaBrowser.ServerApplication/packages.config2
105 files changed, 1447 insertions, 8987 deletions
diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs
index 47d199e6e..7db282dc8 100644
--- a/Emby.Dlna/ContentDirectory/ControlHandler.cs
+++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs
@@ -1101,7 +1101,7 @@ namespace Emby.Dlna.ContentDirectory
StartIndex = query.StartIndex,
UserId = query.User.Id.ToString("N")
- }, new List<Folder> { (Folder)parent }, query.DtoOptions);
+ }, new List<BaseItem> { parent }, query.DtoOptions);
return ToResult(result);
}
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index 844a6a5ce..5e200428a 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -209,8 +209,8 @@ namespace Emby.Dlna.Didl
var targetHeight = streamInfo.TargetHeight;
var contentFeatureList = new ContentFeatureBuilder(_profile).BuildVideoHeader(streamInfo.Container,
- streamInfo.TargetVideoCodec,
- streamInfo.TargetAudioCodec,
+ streamInfo.TargetVideoCodec.FirstOrDefault(),
+ streamInfo.TargetAudioCodec.FirstOrDefault(),
targetWidth,
targetHeight,
streamInfo.TargetVideoBitDepth,
@@ -353,8 +353,8 @@ namespace Emby.Dlna.Didl
}
var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container,
- streamInfo.TargetAudioCodec,
- streamInfo.TargetVideoCodec,
+ streamInfo.TargetAudioCodec.FirstOrDefault(),
+ streamInfo.TargetVideoCodec.FirstOrDefault(),
streamInfo.TargetAudioBitrate,
targetWidth,
targetHeight,
@@ -554,7 +554,7 @@ namespace Emby.Dlna.Didl
}
var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container,
- streamInfo.TargetAudioCodec,
+ streamInfo.TargetAudioCodec.FirstOrDefault(),
targetChannels,
targetAudioBitrate,
targetSampleRate,
@@ -567,7 +567,7 @@ namespace Emby.Dlna.Didl
: mediaProfile.MimeType;
var contentFeatures = new ContentFeatureBuilder(_profile).BuildAudioHeader(streamInfo.Container,
- streamInfo.TargetAudioCodec,
+ streamInfo.TargetAudioCodec.FirstOrDefault(),
targetAudioBitrate,
targetSampleRate,
targetChannels,
@@ -1141,17 +1141,17 @@ namespace Emby.Dlna.Didl
int? width = null;
int? height = null;
- try
- {
- var size = _imageProcessor.GetImageSize(imageInfo);
+ //try
+ //{
+ // var size = _imageProcessor.GetImageSize(imageInfo);
- width = Convert.ToInt32(size.Width);
- height = Convert.ToInt32(size.Height);
- }
- catch
- {
+ // width = Convert.ToInt32(size.Width);
+ // height = Convert.ToInt32(size.Height);
+ //}
+ //catch
+ //{
- }
+ //}
var inputFormat = (Path.GetExtension(imageInfo.Path) ?? string.Empty)
.TrimStart('.')
diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs
index b6b1c0c03..165f123f1 100644
--- a/Emby.Dlna/PlayTo/Device.cs
+++ b/Emby.Dlna/PlayTo/Device.cs
@@ -662,7 +662,33 @@ namespace Emby.Dlna.PlayTo
var e = track.Element(uPnpNamespaces.items) ?? track;
- return UpnpContainer.Create(e);
+ var elementString = (string)e;
+
+ if (!string.IsNullOrWhiteSpace(elementString))
+ {
+ return UpnpContainer.Create(e);
+ }
+
+ track = result.Document.Descendants("CurrentURI").FirstOrDefault();
+
+ if (track == null)
+ {
+ return null;
+ }
+
+ e = track.Element(uPnpNamespaces.items) ?? track;
+
+ elementString = (string)e;
+
+ if (!string.IsNullOrWhiteSpace(elementString))
+ {
+ return new uBaseObject
+ {
+ Url = elementString
+ };
+ }
+
+ return null;
}
private async Task<Tuple<bool, uBaseObject>> GetPositionInfo()
@@ -720,7 +746,7 @@ namespace Emby.Dlna.PlayTo
if (string.IsNullOrWhiteSpace(trackString) || string.Equals(trackString, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
{
- return new Tuple<bool, uBaseObject>(false, null);
+ return new Tuple<bool, uBaseObject>(true, null);
}
XElement uPnpResponse;
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index 95b164212..ba1d3a6de 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -13,6 +13,7 @@ using MediaBrowser.Model.System;
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
@@ -515,7 +516,7 @@ namespace Emby.Dlna.PlayTo
{
return new ContentFeatureBuilder(profile)
.BuildAudioHeader(streamInfo.Container,
- streamInfo.TargetAudioCodec,
+ streamInfo.TargetAudioCodec.FirstOrDefault(),
streamInfo.TargetAudioBitrate,
streamInfo.TargetAudioSampleRate,
streamInfo.TargetAudioChannels,
@@ -529,8 +530,8 @@ namespace Emby.Dlna.PlayTo
{
var list = new ContentFeatureBuilder(profile)
.BuildVideoHeader(streamInfo.Container,
- streamInfo.TargetVideoCodec,
- streamInfo.TargetAudioCodec,
+ streamInfo.TargetVideoCodec.FirstOrDefault(),
+ streamInfo.TargetAudioCodec.FirstOrDefault(),
streamInfo.TargetWidth,
streamInfo.TargetHeight,
streamInfo.TargetVideoBitDepth,
diff --git a/Emby.Dlna/Profiles/LgTvProfile.cs b/Emby.Dlna/Profiles/LgTvProfile.cs
index f81fb1ee7..33185365c 100644
--- a/Emby.Dlna/Profiles/LgTvProfile.cs
+++ b/Emby.Dlna/Profiles/LgTvProfile.cs
@@ -55,14 +55,14 @@ namespace Emby.Dlna.Profiles
{
Container = "ts,mpegts,avi,mkv",
VideoCodec = "h264",
- AudioCodec = "aac,ac3,mp3,dca,dts",
+ AudioCodec = "aac,ac3,eac3,mp3,dca,dts",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4,m4v",
VideoCodec = "h264,mpeg4",
- AudioCodec = "aac,ac3,mp3,dca,dts",
+ AudioCodec = "aac,ac3,eac3,mp3,dca,dts",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
@@ -168,7 +168,7 @@ namespace Emby.Dlna.Profiles
new CodecProfile
{
Type = CodecType.VideoAudio,
- Codec = "ac3,aac,mp3",
+ Codec = "ac3,eac3,aac,mp3",
Conditions = new[]
{
diff --git a/Emby.Dlna/Profiles/Xml/LG Smart TV.xml b/Emby.Dlna/Profiles/Xml/LG Smart TV.xml
index 92e02799e..ac8c8194c 100644
--- a/Emby.Dlna/Profiles/Xml/LG Smart TV.xml
+++ b/Emby.Dlna/Profiles/Xml/LG Smart TV.xml
@@ -35,8 +35,8 @@
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
<XmlRootAttributes />
<DirectPlayProfiles>
- <DirectPlayProfile container="ts,mpegts,avi,mkv" audioCodec="aac,ac3,mp3,dca,dts" videoCodec="h264" type="Video" />
- <DirectPlayProfile container="mp4,m4v" audioCodec="aac,ac3,mp3,dca,dts" videoCodec="h264,mpeg4" type="Video" />
+ <DirectPlayProfile container="ts,mpegts,avi,mkv" audioCodec="aac,ac3,eac3,mp3,dca,dts" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="mp4,m4v" audioCodec="aac,ac3,eac3,mp3,dca,dts" videoCodec="h264,mpeg4" type="Video" />
<DirectPlayProfile container="mp3" type="Audio" />
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
@@ -71,7 +71,7 @@
</Conditions>
<ApplyConditions />
</CodecProfile>
- <CodecProfile type="VideoAudio" codec="ac3,aac,mp3">
+ <CodecProfile type="VideoAudio" codec="ac3,eac3,aac,mp3">
<Conditions>
<ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
</Conditions>
diff --git a/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs
index 2c40bf570..04f916eb1 100644
--- a/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs
+++ b/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs
@@ -148,7 +148,6 @@ namespace Emby.Drawing.ImageMagick
}
var originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
- ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize))
{
@@ -182,7 +181,6 @@ namespace Emby.Drawing.ImageMagick
using (var originalImage = new MagickWand(inputPath))
{
var originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
- ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize);
@@ -343,13 +341,6 @@ namespace Emby.Drawing.ImageMagick
{
get
{
- // too heavy. seeing crashes on RPI.
- if (_environment.SystemArchitecture == Architecture.Arm ||
- _environment.SystemArchitecture == Architecture.Arm64)
- {
- return false;
- }
-
return true;
}
}
diff --git a/Emby.Drawing.Skia/SkiaEncoder.cs b/Emby.Drawing.Skia/SkiaEncoder.cs
index eb0602afe..7469d167e 100644
--- a/Emby.Drawing.Skia/SkiaEncoder.cs
+++ b/Emby.Drawing.Skia/SkiaEncoder.cs
@@ -40,7 +40,9 @@ namespace Emby.Drawing.Skia
"jpeg",
"jpg",
"png",
+
"dng",
+
"webp",
"gif",
"bmp",
@@ -51,7 +53,8 @@ namespace Emby.Drawing.Skia
"wbmp",
// working on windows at least
- "cr2"
+ "cr2",
+ "nef"
};
}
}
@@ -459,7 +462,6 @@ namespace Emby.Drawing.Skia
//_logger.Info("Color type {0}", bitmap.Info.ColorType);
var originalImageSize = new ImageSize(bitmap.Width, bitmap.Height);
- ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize) && !autoOrient)
{
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index f5a05db05..831454972 100644
--- a/Emby.Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -36,11 +36,6 @@ namespace Emby.Drawing
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
/// <summary>
- /// The _cached imaged sizes
- /// </summary>
- private readonly ConcurrentDictionary<Guid, ImageSize> _cachedImagedSizes;
-
- /// <summary>
/// Gets the list of currently registered image processors
/// Image processors are specialized metadata providers that run after the normal ones
/// </summary>
@@ -75,34 +70,7 @@ namespace Emby.Drawing
_appPaths = appPaths;
ImageEnhancers = new IImageEnhancer[] { };
- _saveImageSizeTimer = timerFactory.Create(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite);
ImageHelper.ImageProcessor = this;
-
- Dictionary<Guid, ImageSize> sizeDictionary;
-
- try
- {
- sizeDictionary = jsonSerializer.DeserializeFromFile<Dictionary<Guid, ImageSize>>(ImageSizeFile) ??
- new Dictionary<Guid, ImageSize>();
- }
- catch (FileNotFoundException)
- {
- // No biggie
- sizeDictionary = new Dictionary<Guid, ImageSize>();
- }
- catch (IOException)
- {
- // No biggie
- sizeDictionary = new Dictionary<Guid, ImageSize>();
- }
- catch (Exception ex)
- {
- logger.ErrorException("Error parsing image size cache file", ex);
-
- sizeDictionary = new Dictionary<Guid, ImageSize>();
- }
-
- _cachedImagedSizes = new ConcurrentDictionary<Guid, ImageSize>(sizeDictionary);
}
public IImageEncoder ImageEncoder
@@ -133,7 +101,6 @@ namespace Emby.Drawing
"aiff",
"cr2",
"crw",
- "dng",
// Remove until supported
//"nef",
@@ -275,15 +242,15 @@ namespace Emby.Drawing
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
- ImageSize? originalImageSize = GetSavedImageSize(originalImagePath, dateModified);
- if (originalImageSize.HasValue && options.HasDefaultOptions(originalImagePath, originalImageSize.Value) && !autoOrient)
- {
- // Just spit out the original file if all the options are default
- _logger.Info("Returning original image {0}", originalImagePath);
- return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
- }
+ //ImageSize? originalImageSize = GetSavedImageSize(originalImagePath, dateModified);
+ //if (originalImageSize.HasValue && options.HasDefaultOptions(originalImagePath, originalImageSize.Value) && !autoOrient)
+ //{
+ // // Just spit out the original file if all the options are default
+ // _logger.Info("Returning original image {0}", originalImagePath);
+ // return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
+ //}
- var newSize = ImageHelper.GetNewImageSize(options, originalImageSize);
+ var newSize = ImageHelper.GetNewImageSize(options, null);
var quality = options.Quality;
var outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency);
@@ -477,98 +444,30 @@ namespace Emby.Drawing
public ImageSize GetImageSize(ItemImageInfo info, bool allowSlowMethods)
{
- return GetImageSize(info.Path, info.DateModified, allowSlowMethods);
+ return GetImageSize(info.Path, allowSlowMethods);
}
public ImageSize GetImageSize(ItemImageInfo info)
{
- return GetImageSize(info.Path, info.DateModified, false);
+ return GetImageSize(info.Path, false);
}
public ImageSize GetImageSize(string path)
{
- return GetImageSize(path, _fileSystem.GetLastWriteTimeUtc(path), false);
+ return GetImageSize(path, false);
}
/// <summary>
/// Gets the size of the image.
/// </summary>
- /// <param name="path">The path.</param>
- /// <param name="imageDateModified">The image date modified.</param>
- /// <param name="allowSlowMethod">if set to <c>true</c> [allow slow method].</param>
- /// <returns>ImageSize.</returns>
- /// <exception cref="System.ArgumentNullException">path</exception>
- private ImageSize GetImageSize(string path, DateTime imageDateModified, bool allowSlowMethod)
+ private ImageSize GetImageSize(string path, bool allowSlowMethod)
{
if (string.IsNullOrEmpty(path))
{
throw new ArgumentNullException("path");
}
- ImageSize size;
-
- var cacheHash = GetImageSizeKey(path, imageDateModified);
-
- if (!_cachedImagedSizes.TryGetValue(cacheHash, out size))
- {
- size = GetImageSizeInternal(path, allowSlowMethod);
-
- SaveImageSize(size, cacheHash, false);
- }
-
- return size;
- }
-
- public void SaveImageSize(string path, DateTime imageDateModified, ImageSize size)
- {
- var cacheHash = GetImageSizeKey(path, imageDateModified);
- SaveImageSize(size, cacheHash, true);
- }
-
- private void SaveImageSize(ImageSize size, Guid cacheHash, bool checkExists)
- {
- if (size.Width <= 0 || size.Height <= 0)
- {
- return;
- }
-
- if (checkExists && _cachedImagedSizes.ContainsKey(cacheHash))
- {
- return;
- }
-
- if (checkExists)
- {
- if (_cachedImagedSizes.TryAdd(cacheHash, size))
- {
- StartSaveImageSizeTimer();
- }
- }
- else
- {
- StartSaveImageSizeTimer();
- _cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size);
- }
- }
-
- private Guid GetImageSizeKey(string path, DateTime imageDateModified)
- {
- var name = path + "datemodified=" + imageDateModified.Ticks;
- return name.GetMD5();
- }
-
- public ImageSize? GetSavedImageSize(string path, DateTime imageDateModified)
- {
- ImageSize size;
-
- var cacheHash = GetImageSizeKey(path, imageDateModified);
-
- if (_cachedImagedSizes.TryGetValue(cacheHash, out size))
- {
- return size;
- }
-
- return null;
+ return GetImageSizeInternal(path, allowSlowMethod);
}
/// <summary>
@@ -619,39 +518,6 @@ namespace Emby.Drawing
}
}
- private readonly ITimer _saveImageSizeTimer;
- private const int SaveImageSizeTimeout = 5000;
- private readonly object _saveImageSizeLock = new object();
- private void StartSaveImageSizeTimer()
- {
- _saveImageSizeTimer.Change(SaveImageSizeTimeout, Timeout.Infinite);
- }
-
- private void SaveImageSizeCallback(object state)
- {
- lock (_saveImageSizeLock)
- {
- try
- {
- var path = ImageSizeFile;
- _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path));
- _jsonSerializer.SerializeToFile(_cachedImagedSizes, path);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving image size file", ex);
- }
- }
- }
-
- private string ImageSizeFile
- {
- get
- {
- return Path.Combine(_appPaths.DataPath, "imagesizes.json");
- }
- }
-
/// <summary>
/// Gets the image cache tag.
/// </summary>
@@ -1016,7 +882,6 @@ namespace Emby.Drawing
disposable.Dispose();
}
- _saveImageSizeTimer.Dispose();
GC.SuppressFinalize(this);
}
diff --git a/Emby.Photos/PhotoProvider.cs b/Emby.Photos/PhotoProvider.cs
index c3c30ab6d..fe77cff69 100644
--- a/Emby.Photos/PhotoProvider.cs
+++ b/Emby.Photos/PhotoProvider.cs
@@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@@ -20,134 +21,152 @@ namespace Emby.Photos
{
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
+ private IImageProcessor _imageProcessor;
- public PhotoProvider(ILogger logger, IFileSystem fileSystem)
+ public PhotoProvider(ILogger logger, IFileSystem fileSystem, IImageProcessor imageProcessor)
{
_logger = logger;
_fileSystem = fileSystem;
+ _imageProcessor = imageProcessor;
}
+ // These are causing taglib to hang
+ private string[] _excludeExtensions = new string[] { ".dng" };
+
public Task<ItemUpdateType> FetchAsync(Photo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
{
item.SetImagePath(ImageType.Primary, item.Path);
// Examples: https://github.com/mono/taglib-sharp/blob/a5f6949a53d09ce63ee7495580d6802921a21f14/tests/fixtures/TagLib.Tests.Images/NullOrientationTest.cs
-
- try
+ if (!_excludeExtensions.Contains(Path.GetExtension(item.Path) ?? string.Empty, StringComparer.OrdinalIgnoreCase))
{
- using (var fileStream = _fileSystem.OpenRead(item.Path))
+ try
{
- using (var file = TagLib.File.Create(new StreamFileAbstraction(Path.GetFileName(item.Path), fileStream, null)))
+ using (var fileStream = _fileSystem.OpenRead(item.Path))
{
- var image = file as TagLib.Image.File;
-
- var tag = file.GetTag(TagTypes.TiffIFD) as IFDTag;
-
- if (tag != null)
+ using (var file = TagLib.File.Create(new StreamFileAbstraction(Path.GetFileName(item.Path), fileStream, null)))
{
- var structure = tag.Structure;
+ var image = file as TagLib.Image.File;
- if (structure != null)
+ var tag = file.GetTag(TagTypes.TiffIFD) as IFDTag;
+
+ if (tag != null)
{
- var exif = structure.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry;
+ var structure = tag.Structure;
- if (exif != null)
+ if (structure != null)
{
- var exifStructure = exif.Structure;
+ var exif = structure.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry;
- if (exifStructure != null)
+ if (exif != null)
{
- var entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) as RationalIFDEntry;
+ var exifStructure = exif.Structure;
- if (entry != null)
+ if (exifStructure != null)
{
- double val = entry.Value.Numerator;
- val /= entry.Value.Denominator;
- item.Aperture = val;
- }
-
- entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) as RationalIFDEntry;
-
- if (entry != null)
- {
- double val = entry.Value.Numerator;
- val /= entry.Value.Denominator;
- item.ShutterSpeed = val;
+ var entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) as RationalIFDEntry;
+
+ if (entry != null)
+ {
+ double val = entry.Value.Numerator;
+ val /= entry.Value.Denominator;
+ item.Aperture = val;
+ }
+
+ entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) as RationalIFDEntry;
+
+ if (entry != null)
+ {
+ double val = entry.Value.Numerator;
+ val /= entry.Value.Denominator;
+ item.ShutterSpeed = val;
+ }
}
}
}
}
- }
- item.CameraMake = image.ImageTag.Make;
- item.CameraModel = image.ImageTag.Model;
+ if (image != null)
+ {
+ item.CameraMake = image.ImageTag.Make;
+ item.CameraModel = image.ImageTag.Model;
- item.Width = image.Properties.PhotoWidth;
- item.Height = image.Properties.PhotoHeight;
+ item.Width = image.Properties.PhotoWidth;
+ item.Height = image.Properties.PhotoHeight;
- var rating = image.ImageTag.Rating;
- if (rating.HasValue)
- {
- item.CommunityRating = rating;
- }
- else
- {
- item.CommunityRating = null;
- }
+ var rating = image.ImageTag.Rating;
+ if (rating.HasValue)
+ {
+ item.CommunityRating = rating;
+ }
+ else
+ {
+ item.CommunityRating = null;
+ }
- item.Overview = image.ImageTag.Comment;
+ item.Overview = image.ImageTag.Comment;
- if (!string.IsNullOrWhiteSpace(image.ImageTag.Title))
- {
- item.Name = image.ImageTag.Title;
- }
+ if (!string.IsNullOrWhiteSpace(image.ImageTag.Title))
+ {
+ item.Name = image.ImageTag.Title;
+ }
- var dateTaken = image.ImageTag.DateTime;
- if (dateTaken.HasValue)
- {
- item.DateCreated = dateTaken.Value;
- item.PremiereDate = dateTaken.Value;
- item.ProductionYear = dateTaken.Value.Year;
- }
+ var dateTaken = image.ImageTag.DateTime;
+ if (dateTaken.HasValue)
+ {
+ item.DateCreated = dateTaken.Value;
+ item.PremiereDate = dateTaken.Value;
+ item.ProductionYear = dateTaken.Value.Year;
+ }
- item.Genres = image.ImageTag.Genres.ToList();
- item.Tags = image.ImageTag.Keywords;
- item.Software = image.ImageTag.Software;
+ item.Genres = image.ImageTag.Genres.ToList();
+ item.Tags = image.ImageTag.Keywords;
+ item.Software = image.ImageTag.Software;
- if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
- {
- item.Orientation = null;
- }
- else
- {
- MediaBrowser.Model.Drawing.ImageOrientation orientation;
- if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation))
- {
- item.Orientation = orientation;
- }
- }
+ if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
+ {
+ item.Orientation = null;
+ }
+ else
+ {
+ MediaBrowser.Model.Drawing.ImageOrientation orientation;
+ if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation))
+ {
+ item.Orientation = orientation;
+ }
+ }
- item.ExposureTime = image.ImageTag.ExposureTime;
- item.FocalLength = image.ImageTag.FocalLength;
+ item.ExposureTime = image.ImageTag.ExposureTime;
+ item.FocalLength = image.ImageTag.FocalLength;
- item.Latitude = image.ImageTag.Latitude;
- item.Longitude = image.ImageTag.Longitude;
- item.Altitude = image.ImageTag.Altitude;
+ item.Latitude = image.ImageTag.Latitude;
+ item.Longitude = image.ImageTag.Longitude;
+ item.Altitude = image.ImageTag.Altitude;
- if (image.ImageTag.ISOSpeedRatings.HasValue)
- {
- item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value);
- }
- else
- {
- item.IsoSpeedRating = null;
+ if (image.ImageTag.ISOSpeedRatings.HasValue)
+ {
+ item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value);
+ }
+ else
+ {
+ item.IsoSpeedRating = null;
+ }
+ }
}
}
}
+ catch (Exception e)
+ {
+ _logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path);
+ }
}
- catch (Exception e)
+
+ if (!item.Width.HasValue || !item.Height.HasValue)
{
- _logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path);
+ var size = _imageProcessor.GetImageSize(item.Path);
+
+ item.Width = Convert.ToInt32(size.Width);
+ item.Height = Convert.ToInt32(size.Height);
}
const ItemUpdateType result = ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataImport;
diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs
index 3dcc50ba3..1ae8e5e66 100644
--- a/Emby.Server.Implementations/Activity/ActivityRepository.cs
+++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs
@@ -10,21 +10,40 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
using SQLitePCL.pretty;
using MediaBrowser.Model.Extensions;
+using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Activity
{
public class ActivityRepository : BaseSqliteRepository, IActivityRepository
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+ protected IFileSystem FileSystem { get; private set; }
- public ActivityRepository(ILogger logger, IServerApplicationPaths appPaths)
+ public ActivityRepository(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem)
: base(logger)
{
DbFilePath = Path.Combine(appPaths.DataPath, "activitylog.db");
+ FileSystem = fileSystem;
}
public void Initialize()
{
+ try
+ {
+ InitializeInternal();
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error loading database file. Will reset and retry.", ex);
+
+ FileSystem.DeleteFile(DbFilePath);
+
+ InitializeInternal();
+ }
+ }
+
+ private void InitializeInternal()
+ {
using (var connection = CreateConnection())
{
RunDefaultInitialization(connection);
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 713ece421..57c509923 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -7,7 +7,6 @@ using Emby.Dlna.MediaReceiverRegistrar;
using Emby.Dlna.Ssdp;
using Emby.Drawing;
using Emby.Photos;
-using Emby.Server.Core.Cryptography;
using Emby.Server.Implementations.Activity;
using Emby.Server.Implementations.Archiving;
using Emby.Server.Implementations.Channels;
@@ -879,7 +878,7 @@ namespace Emby.Server.Implementations
// This is only needed for disposal purposes. If removing this, make sure to have the manager handle disposing it
RegisterSingleInstance(UserRepository);
- var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager.GetLogger("SqliteDisplayPreferencesRepository"), JsonSerializer, ApplicationPaths, MemoryStreamFactory);
+ var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager.GetLogger("SqliteDisplayPreferencesRepository"), JsonSerializer, ApplicationPaths, MemoryStreamFactory, FileSystemManager);
DisplayPreferencesRepository = displayPreferencesRepo;
RegisterSingleInstance(DisplayPreferencesRepository);
@@ -997,7 +996,7 @@ namespace Emby.Server.Implementations
EncodingManager = new EncodingManager(FileSystemManager, Logger, MediaEncoder, ChapterManager, LibraryManager);
RegisterSingleInstance(EncodingManager);
- var sharingRepo = new SharingRepository(LogManager.GetLogger("SharingRepository"), ApplicationPaths);
+ var sharingRepo = new SharingRepository(LogManager.GetLogger("SharingRepository"), ApplicationPaths, FileSystemManager);
sharingRepo.Initialize();
// This is only needed for disposal purposes. If removing this, make sure to have the manager handle disposing it
RegisterSingleInstance<ISharingRepository>(sharingRepo);
@@ -1351,7 +1350,7 @@ namespace Emby.Server.Implementations
private IActivityRepository GetActivityLogRepository()
{
- var repo = new ActivityRepository(LogManager.GetLogger("ActivityRepository"), ServerConfigurationManager.ApplicationPaths);
+ var repo = new ActivityRepository(LogManager.GetLogger("ActivityRepository"), ServerConfigurationManager.ApplicationPaths, FileSystemManager);
repo.Initialize();
@@ -1640,23 +1639,23 @@ namespace Emby.Server.Implementations
var certPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.ProgramDataPath, "ssl", "cert_" + (certHost + "2").GetMD5().ToString("N") + ".pfx");
var password = "embycert";
- if (generateCertificate)
- {
- if (!FileSystemManager.FileExists(certPath))
- {
- FileSystemManager.CreateDirectory(FileSystemManager.GetDirectoryName(certPath));
-
- try
- {
- CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, password, Logger);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error creating ssl cert", ex);
- return null;
- }
- }
- }
+ //if (generateCertificate)
+ //{
+ // if (!FileSystemManager.FileExists(certPath))
+ // {
+ // FileSystemManager.CreateDirectory(FileSystemManager.GetDirectoryName(certPath));
+
+ // try
+ // {
+ // CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, password, Logger);
+ // }
+ // catch (Exception ex)
+ // {
+ // Logger.ErrorException("Error creating ssl cert", ex);
+ // return null;
+ // }
+ // }
+ //}
return new CertificateInfo
{
@@ -1932,13 +1931,13 @@ namespace Emby.Server.Implementations
{
get
{
- return SupportsHttps && ServerConfigurationManager.Configuration.EnableHttps;
+ return SupportsHttps && (ServerConfigurationManager.Configuration.EnableHttps || ServerConfigurationManager.Configuration.RequireHttps);
}
}
public bool SupportsHttps
{
- get { return Certificate != null; }
+ get { return Certificate != null || ServerConfigurationManager.Configuration.IsBehindProxy; }
}
public async Task<string> GetLocalApiUrl()
@@ -2208,22 +2207,39 @@ namespace Emby.Server.Implementations
{
var updateLevel = SystemUpdateLevel;
var cacheLength = updateLevel == PackageVersionClass.Release ?
- TimeSpan.FromHours(4) :
+ TimeSpan.FromHours(12) :
TimeSpan.FromMinutes(5);
- var result = await new GithubUpdater(HttpClient, JsonSerializer).CheckForUpdateResult("MediaBrowser",
- "Emby",
- ApplicationVersion,
- updateLevel,
- ReleaseAssetFilename,
- "MBServer",
- UpdateTargetFileName,
- cacheLength,
- cancellationToken).ConfigureAwait(false);
+ try
+ {
+ var result = await new GithubUpdater(HttpClient, JsonSerializer).CheckForUpdateResult("MediaBrowser",
+ "Emby",
+ ApplicationVersion,
+ updateLevel,
+ ReleaseAssetFilename,
+ "MBServer",
+ UpdateTargetFileName,
+ cacheLength,
+ cancellationToken).ConfigureAwait(false);
+
+ HasUpdateAvailable = result.IsUpdateAvailable;
- HasUpdateAvailable = result.IsUpdateAvailable;
+ return result;
+ }
+ catch (HttpException ex)
+ {
+ // users are overreacting to this occasionally failing
+ if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.Forbidden)
+ {
+ HasUpdateAvailable = false;
+ return new CheckForUpdateResult
+ {
+ IsUpdateAvailable = false
+ };
+ }
- return result;
+ throw;
+ }
}
protected virtual string UpdateTargetFileName
diff --git a/Emby.Server.Implementations/Archiving/ZipClient.cs b/Emby.Server.Implementations/Archiving/ZipClient.cs
index 3218d56c6..d7d37bb61 100644
--- a/Emby.Server.Implementations/Archiving/ZipClient.cs
+++ b/Emby.Server.Implementations/Archiving/ZipClient.cs
@@ -4,6 +4,7 @@ using SharpCompress.Archives.Rar;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Archives.Tar;
using SharpCompress.Readers;
+using SharpCompress.Readers.GZip;
using SharpCompress.Readers.Zip;
namespace Emby.Server.Implementations.Archiving
@@ -72,6 +73,22 @@ namespace Emby.Server.Implementations.Archiving
}
}
+ public void ExtractAllFromGz(Stream source, string targetPath, bool overwriteExistingFiles)
+ {
+ using (var reader = GZipReader.Open(source))
+ {
+ var options = new ExtractionOptions();
+ options.ExtractFullPath = true;
+
+ if (overwriteExistingFiles)
+ {
+ options.Overwrite = true;
+ }
+
+ reader.WriteAllToDirectory(targetPath, options);
+ }
+ }
+
/// <summary>
/// Extracts all from7z.
/// </summary>
diff --git a/Emby.Server.Implementations/Cryptography/ASN1.cs b/Emby.Server.Implementations/Cryptography/ASN1.cs
deleted file mode 100644
index f5c826436..000000000
--- a/Emby.Server.Implementations/Cryptography/ASN1.cs
+++ /dev/null
@@ -1,340 +0,0 @@
-//
-// ASN1.cs: Abstract Syntax Notation 1 - micro-parser and generator
-//
-// Authors:
-// Sebastien Pouliot <sebastien@ximian.com>
-// Jesper Pedersen <jep@itplus.dk>
-//
-// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
-// (C) 2004 IT+ A/S (http://www.itplus.dk)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Collections;
-using System.IO;
-using System.Text;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- // References:
- // a. ITU ASN.1 standards (free download)
- // http://www.itu.int/ITU-T/studygroups/com17/languages/
-
- public class ASN1 {
-
- private byte m_nTag;
- private byte[] m_aValue;
- private ArrayList elist;
-
- public ASN1 () : this (0x00, null) {}
-
- public ASN1 (byte tag) : this (tag, null) {}
-
- public ASN1 (byte tag, byte[] data)
- {
- m_nTag = tag;
- m_aValue = data;
- }
-
- public ASN1 (byte[] data)
- {
- m_nTag = data [0];
-
- int nLenLength = 0;
- int nLength = data [1];
-
- if (nLength > 0x80) {
- // composed length
- nLenLength = nLength - 0x80;
- nLength = 0;
- for (int i = 0; i < nLenLength; i++) {
- nLength *= 256;
- nLength += data [i + 2];
- }
- }
- else if (nLength == 0x80) {
- // undefined length encoding
- throw new NotSupportedException ("Undefined length encoding.");
- }
-
- m_aValue = new byte [nLength];
- Buffer.BlockCopy (data, (2 + nLenLength), m_aValue, 0, nLength);
-
- if ((m_nTag & 0x20) == 0x20) {
- int nStart = (2 + nLenLength);
- Decode (data, ref nStart, data.Length);
- }
- }
-
- public int Count {
- get {
- if (elist == null)
- return 0;
- return elist.Count;
- }
- }
-
- public byte Tag {
- get { return m_nTag; }
- }
-
- public int Length {
- get {
- if (m_aValue != null)
- return m_aValue.Length;
- else
- return 0;
- }
- }
-
- public byte[] Value {
- get {
- if (m_aValue == null)
- GetBytes ();
- return (byte[]) m_aValue.Clone ();
- }
- set {
- if (value != null)
- m_aValue = (byte[]) value.Clone ();
- }
- }
-
- private bool CompareArray (byte[] array1, byte[] array2)
- {
- bool bResult = (array1.Length == array2.Length);
- if (bResult) {
- for (int i = 0; i < array1.Length; i++) {
- if (array1[i] != array2[i])
- return false;
- }
- }
- return bResult;
- }
-
- public bool Equals (byte[] asn1)
- {
- return CompareArray (this.GetBytes (), asn1);
- }
-
- public bool CompareValue (byte[] value)
- {
- return CompareArray (m_aValue, value);
- }
-
- public ASN1 Add (ASN1 asn1)
- {
- if (asn1 != null) {
- if (elist == null)
- elist = new ArrayList ();
- elist.Add (asn1);
- }
- return asn1;
- }
-
- public virtual byte[] GetBytes ()
- {
- byte[] val = null;
-
- if (Count > 0) {
- int esize = 0;
- ArrayList al = new ArrayList ();
- foreach (ASN1 a in elist) {
- byte[] item = a.GetBytes ();
- al.Add (item);
- esize += item.Length;
- }
- val = new byte [esize];
- int pos = 0;
- for (int i=0; i < elist.Count; i++) {
- byte[] item = (byte[]) al[i];
- Buffer.BlockCopy (item, 0, val, pos, item.Length);
- pos += item.Length;
- }
- } else if (m_aValue != null) {
- val = m_aValue;
- }
-
- byte[] der;
- int nLengthLen = 0;
-
- if (val != null) {
- int nLength = val.Length;
- // special for length > 127
- if (nLength > 127) {
- if (nLength <= Byte.MaxValue) {
- der = new byte [3 + nLength];
- Buffer.BlockCopy (val, 0, der, 3, nLength);
- nLengthLen = 0x81;
- der[2] = (byte)(nLength);
- }
- else if (nLength <= UInt16.MaxValue) {
- der = new byte [4 + nLength];
- Buffer.BlockCopy (val, 0, der, 4, nLength);
- nLengthLen = 0x82;
- der[2] = (byte)(nLength >> 8);
- der[3] = (byte)(nLength);
- }
- else if (nLength <= 0xFFFFFF) {
- // 24 bits
- der = new byte [5 + nLength];
- Buffer.BlockCopy (val, 0, der, 5, nLength);
- nLengthLen = 0x83;
- der [2] = (byte)(nLength >> 16);
- der [3] = (byte)(nLength >> 8);
- der [4] = (byte)(nLength);
- }
- else {
- // max (Length is an integer) 32 bits
- der = new byte [6 + nLength];
- Buffer.BlockCopy (val, 0, der, 6, nLength);
- nLengthLen = 0x84;
- der [2] = (byte)(nLength >> 24);
- der [3] = (byte)(nLength >> 16);
- der [4] = (byte)(nLength >> 8);
- der [5] = (byte)(nLength);
- }
- }
- else {
- // basic case (no encoding)
- der = new byte [2 + nLength];
- Buffer.BlockCopy (val, 0, der, 2, nLength);
- nLengthLen = nLength;
- }
- if (m_aValue == null)
- m_aValue = val;
- }
- else
- der = new byte[2];
-
- der[0] = m_nTag;
- der[1] = (byte)nLengthLen;
-
- return der;
- }
-
- // Note: Recursive
- protected void Decode (byte[] asn1, ref int anPos, int anLength)
- {
- byte nTag;
- int nLength;
- byte[] aValue;
-
- // minimum is 2 bytes (tag + length of 0)
- while (anPos < anLength - 1) {
- DecodeTLV (asn1, ref anPos, out nTag, out nLength, out aValue);
- // sometimes we get trailing 0
- if (nTag == 0)
- continue;
-
- ASN1 elm = Add (new ASN1 (nTag, aValue));
-
- if ((nTag & 0x20) == 0x20) {
- int nConstructedPos = anPos;
- elm.Decode (asn1, ref nConstructedPos, nConstructedPos + nLength);
- }
- anPos += nLength; // value length
- }
- }
-
- // TLV : Tag - Length - Value
- protected void DecodeTLV (byte[] asn1, ref int pos, out byte tag, out int length, out byte[] content)
- {
- tag = asn1 [pos++];
- length = asn1 [pos++];
-
- // special case where L contains the Length of the Length + 0x80
- if ((length & 0x80) == 0x80) {
- int nLengthLen = length & 0x7F;
- length = 0;
- for (int i = 0; i < nLengthLen; i++)
- length = length * 256 + asn1 [pos++];
- }
-
- content = new byte [length];
- Buffer.BlockCopy (asn1, pos, content, 0, length);
- }
-
- public ASN1 this [int index] {
- get {
- try {
- if ((elist == null) || (index >= elist.Count))
- return null;
- return (ASN1) elist [index];
- }
- catch (ArgumentOutOfRangeException) {
- return null;
- }
- }
- }
-
- public ASN1 Element (int index, byte anTag)
- {
- try {
- if ((elist == null) || (index >= elist.Count))
- return null;
-
- ASN1 elm = (ASN1) elist [index];
- if (elm.Tag == anTag)
- return elm;
- else
- return null;
- }
- catch (ArgumentOutOfRangeException) {
- return null;
- }
- }
-
- public override string ToString()
- {
- StringBuilder hexLine = new StringBuilder ();
-
- // Add tag
- hexLine.AppendFormat ("Tag: {0} {1}", m_nTag.ToString ("X2"), Environment.NewLine);
-
- // Add length
- hexLine.AppendFormat ("Length: {0} {1}", Value.Length, Environment.NewLine);
-
- // Add value
- hexLine.Append ("Value: ");
- hexLine.Append (Environment.NewLine);
- for (int i = 0; i < Value.Length; i++) {
- hexLine.AppendFormat ("{0} ", Value [i].ToString ("X2"));
- if ((i+1) % 16 == 0)
- hexLine.AppendFormat (Environment.NewLine);
- }
- return hexLine.ToString ();
- }
-
- public void SaveToFile (string filename)
- {
- if (filename == null)
- throw new ArgumentNullException ("filename");
-
- using (FileStream fs = File.Create (filename)) {
- byte[] data = GetBytes ();
- fs.Write (data, 0, data.Length);
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/ASN1Convert.cs b/Emby.Server.Implementations/Cryptography/ASN1Convert.cs
deleted file mode 100644
index 851d36dc7..000000000
--- a/Emby.Server.Implementations/Cryptography/ASN1Convert.cs
+++ /dev/null
@@ -1,207 +0,0 @@
-//
-// ASN1Convert.cs: Abstract Syntax Notation 1 convertion routines
-//
-// Authors:
-// Sebastien Pouliot <sebastien@ximian.com>
-// Jesper Pedersen <jep@itplus.dk>
-//
-// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// (C) 2004 IT+ A/S (http://www.itplus.dk)
-// Copyright (C) 2004-2007 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Globalization;
-using System.Security.Cryptography;
-using System.Text;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- // References:
- // a. ITU ASN.1 standards (free download)
- // http://www.itu.int/ITU-T/studygroups/com17/languages/
-
- public static class ASN1Convert {
- // RFC3280, section 4.2.1.5
- // CAs conforming to this profile MUST always encode certificate
- // validity dates through the year 2049 as UTCTime; certificate validity
- // dates in 2050 or later MUST be encoded as GeneralizedTime.
-
- // Under 1.x this API requires a Local datetime to be provided
- // Under 2.0 it will also accept a Utc datetime
- static public ASN1 FromDateTime (DateTime dt)
- {
- if (dt.Year < 2050) {
- // UTCTIME
- return new ASN1 (0x17, Encoding.ASCII.GetBytes (
- dt.ToUniversalTime ().ToString ("yyMMddHHmmss",
- CultureInfo.InvariantCulture) + "Z"));
- }
- else {
- // GENERALIZEDTIME
- return new ASN1 (0x18, Encoding.ASCII.GetBytes (
- dt.ToUniversalTime ().ToString ("yyyyMMddHHmmss",
- CultureInfo.InvariantCulture) + "Z"));
- }
- }
-
- static public ASN1 FromInt32 (Int32 value)
- {
- byte[] integer = BitConverterLE.GetBytes (value);
- Array.Reverse (integer);
- int x = 0;
- while ((x < integer.Length) && (integer [x] == 0x00))
- x++;
- ASN1 asn1 = new ASN1 (0x02);
- switch (x) {
- case 0:
- asn1.Value = integer;
- break;
- case 4:
- asn1.Value = new byte [1];
- break;
- default:
- byte[] smallerInt = new byte [4 - x];
- Buffer.BlockCopy (integer, x, smallerInt, 0, smallerInt.Length);
- asn1.Value = smallerInt;
- break;
- }
- return asn1;
- }
-
- static public ASN1 FromOid (string oid)
- {
- if (oid == null)
- throw new ArgumentNullException ("oid");
-
- return new ASN1 (CryptoConfig.EncodeOID (oid));
- }
-
- static public ASN1 FromUnsignedBigInteger (byte[] big)
- {
- if (big == null)
- throw new ArgumentNullException ("big");
-
- // check for numbers that could be interpreted as negative (first bit)
- if (big [0] >= 0x80) {
- // in thie cas we add a new, empty, byte (position 0) so we're
- // sure this will always be interpreted an unsigned integer.
- // However we can't feed it into RSAParameters or DSAParameters
- int length = big.Length + 1;
- byte[] uinteger = new byte [length];
- Buffer.BlockCopy (big, 0, uinteger, 1, length - 1);
- big = uinteger;
- }
- return new ASN1 (0x02, big);
- }
-
- static public int ToInt32 (ASN1 asn1)
- {
- if (asn1 == null)
- throw new ArgumentNullException ("asn1");
- if (asn1.Tag != 0x02)
- throw new FormatException ("Only integer can be converted");
-
- int x = 0;
- for (int i=0; i < asn1.Value.Length; i++)
- x = (x << 8) + asn1.Value [i];
- return x;
- }
-
- // Convert a binary encoded OID to human readable string representation of
- // an OID (IETF style). Based on DUMPASN1.C from Peter Gutmann.
- static public string ToOid (ASN1 asn1)
- {
- if (asn1 == null)
- throw new ArgumentNullException ("asn1");
-
- byte[] aOID = asn1.Value;
- StringBuilder sb = new StringBuilder ();
- // Pick apart the OID
- byte x = (byte) (aOID[0] / 40);
- byte y = (byte) (aOID[0] % 40);
- if (x > 2) {
- // Handle special case for large y if x = 2
- y += (byte) ((x - 2) * 40);
- x = 2;
- }
- sb.Append (x.ToString (CultureInfo.InvariantCulture));
- sb.Append (".");
- sb.Append (y.ToString (CultureInfo.InvariantCulture));
- ulong val = 0;
- for (x = 1; x < aOID.Length; x++) {
- val = ((val << 7) | ((byte) (aOID [x] & 0x7F)));
- if ( !((aOID [x] & 0x80) == 0x80)) {
- sb.Append (".");
- sb.Append (val.ToString (CultureInfo.InvariantCulture));
- val = 0;
- }
- }
- return sb.ToString ();
- }
-
- static public DateTime ToDateTime (ASN1 time)
- {
- if (time == null)
- throw new ArgumentNullException ("time");
-
- string t = Encoding.ASCII.GetString (time.Value);
- // to support both UTCTime and GeneralizedTime (and not so common format)
- string mask = null;
- int year;
- switch (t.Length) {
- case 11:
- // illegal format, still it's supported for compatibility
- mask = "yyMMddHHmmZ";
- break;
- case 13:
- // RFC3280: 4.1.2.5.1 UTCTime
- year = Convert.ToInt16 (t.Substring (0, 2), CultureInfo.InvariantCulture);
- // Where YY is greater than or equal to 50, the
- // year SHALL be interpreted as 19YY; and
- // Where YY is less than 50, the year SHALL be
- // interpreted as 20YY.
- if (year >= 50)
- t = "19" + t;
- else
- t = "20" + t;
- mask = "yyyyMMddHHmmssZ";
- break;
- case 15:
- mask = "yyyyMMddHHmmssZ"; // GeneralizedTime
- break;
- case 17:
- // another illegal format (990630000000+1000), again supported for compatibility
- year = Convert.ToInt16 (t.Substring (0, 2), CultureInfo.InvariantCulture);
- string century = (year >= 50) ? "19" : "20";
- // ASN.1 (see ITU X.680 section 43.3) deals with offset differently than .NET
- char sign = (t[12] == '+') ? '-' : '+';
- t = String.Format ("{0}{1}{2}{3}{4}:{5}{6}", century, t.Substring (0, 12), sign,
- t[13], t[14], t[15], t[16]);
- mask = "yyyyMMddHHmmsszzz";
- break;
- }
- return DateTime.ParseExact (t, mask, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/BitConverterLE.cs b/Emby.Server.Implementations/Cryptography/BitConverterLE.cs
deleted file mode 100644
index 34e6bf6dc..000000000
--- a/Emby.Server.Implementations/Cryptography/BitConverterLE.cs
+++ /dev/null
@@ -1,239 +0,0 @@
-//
-// Mono.Security.BitConverterLE.cs
-// Like System.BitConverter but always little endian
-//
-// Author:
-// Bernie Solomon
-//
-
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-
-namespace Emby.Server.Core.Cryptography
-{
- internal sealed class BitConverterLE
- {
- private BitConverterLE ()
- {
- }
-
- unsafe private static byte[] GetUShortBytes (byte *bytes)
- {
- if (BitConverter.IsLittleEndian)
- return new byte [] { bytes [0], bytes [1] };
- else
- return new byte [] { bytes [1], bytes [0] };
- }
-
- unsafe private static byte[] GetUIntBytes (byte *bytes)
- {
- if (BitConverter.IsLittleEndian)
- return new byte [] { bytes [0], bytes [1], bytes [2], bytes [3] };
- else
- return new byte [] { bytes [3], bytes [2], bytes [1], bytes [0] };
- }
-
- unsafe private static byte[] GetULongBytes (byte *bytes)
- {
- if (BitConverter.IsLittleEndian)
- return new byte [] { bytes [0], bytes [1], bytes [2], bytes [3],
- bytes [4], bytes [5], bytes [6], bytes [7] };
- else
- return new byte [] { bytes [7], bytes [6], bytes [5], bytes [4],
- bytes [3], bytes [2], bytes [1], bytes [0] };
- }
-
- unsafe internal static byte[] GetBytes (bool value)
- {
- return new byte [] { value ? (byte)1 : (byte)0 };
- }
-
- unsafe internal static byte[] GetBytes (char value)
- {
- return GetUShortBytes ((byte *) &value);
- }
-
- unsafe internal static byte[] GetBytes (short value)
- {
- return GetUShortBytes ((byte *) &value);
- }
-
- unsafe internal static byte[] GetBytes (int value)
- {
- return GetUIntBytes ((byte *) &value);
- }
-
- unsafe internal static byte[] GetBytes (long value)
- {
- return GetULongBytes ((byte *) &value);
- }
-
- unsafe internal static byte[] GetBytes (ushort value)
- {
- return GetUShortBytes ((byte *) &value);
- }
-
- unsafe internal static byte[] GetBytes (uint value)
- {
- return GetUIntBytes ((byte *) &value);
- }
-
- unsafe internal static byte[] GetBytes (ulong value)
- {
- return GetULongBytes ((byte *) &value);
- }
-
- unsafe internal static byte[] GetBytes (float value)
- {
- return GetUIntBytes ((byte *) &value);
- }
-
- unsafe internal static byte[] GetBytes (double value)
- {
- return GetULongBytes ((byte *) &value);
- }
-
- unsafe private static void UShortFromBytes (byte *dst, byte[] src, int startIndex)
- {
- if (BitConverter.IsLittleEndian) {
- dst [0] = src [startIndex];
- dst [1] = src [startIndex + 1];
- } else {
- dst [0] = src [startIndex + 1];
- dst [1] = src [startIndex];
- }
- }
-
- unsafe private static void UIntFromBytes (byte *dst, byte[] src, int startIndex)
- {
- if (BitConverter.IsLittleEndian) {
- dst [0] = src [startIndex];
- dst [1] = src [startIndex + 1];
- dst [2] = src [startIndex + 2];
- dst [3] = src [startIndex + 3];
- } else {
- dst [0] = src [startIndex + 3];
- dst [1] = src [startIndex + 2];
- dst [2] = src [startIndex + 1];
- dst [3] = src [startIndex];
- }
- }
-
- unsafe private static void ULongFromBytes (byte *dst, byte[] src, int startIndex)
- {
- if (BitConverter.IsLittleEndian) {
- for (int i = 0; i < 8; ++i)
- dst [i] = src [startIndex + i];
- } else {
- for (int i = 0; i < 8; ++i)
- dst [i] = src [startIndex + (7 - i)];
- }
- }
-
- unsafe internal static bool ToBoolean (byte[] value, int startIndex)
- {
- return value [startIndex] != 0;
- }
-
- unsafe internal static char ToChar (byte[] value, int startIndex)
- {
- char ret;
-
- UShortFromBytes ((byte *) &ret, value, startIndex);
-
- return ret;
- }
-
- unsafe internal static short ToInt16 (byte[] value, int startIndex)
- {
- short ret;
-
- UShortFromBytes ((byte *) &ret, value, startIndex);
-
- return ret;
- }
-
- unsafe internal static int ToInt32 (byte[] value, int startIndex)
- {
- int ret;
-
- UIntFromBytes ((byte *) &ret, value, startIndex);
-
- return ret;
- }
-
- unsafe internal static long ToInt64 (byte[] value, int startIndex)
- {
- long ret;
-
- ULongFromBytes ((byte *) &ret, value, startIndex);
-
- return ret;
- }
-
- unsafe internal static ushort ToUInt16 (byte[] value, int startIndex)
- {
- ushort ret;
-
- UShortFromBytes ((byte *) &ret, value, startIndex);
-
- return ret;
- }
-
- unsafe internal static uint ToUInt32 (byte[] value, int startIndex)
- {
- uint ret;
-
- UIntFromBytes ((byte *) &ret, value, startIndex);
-
- return ret;
- }
-
- unsafe internal static ulong ToUInt64 (byte[] value, int startIndex)
- {
- ulong ret;
-
- ULongFromBytes ((byte *) &ret, value, startIndex);
-
- return ret;
- }
-
- unsafe internal static float ToSingle (byte[] value, int startIndex)
- {
- float ret;
-
- UIntFromBytes ((byte *) &ret, value, startIndex);
-
- return ret;
- }
-
- unsafe internal static double ToDouble (byte[] value, int startIndex)
- {
- double ret;
-
- ULongFromBytes ((byte *) &ret, value, startIndex);
-
- return ret;
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs b/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs
deleted file mode 100644
index b4c84a600..000000000
--- a/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections;
-using System.Security.Cryptography;
-using System.Xml;
-
-namespace Emby.Server.Core.Cryptography
-{
- public class CertificateGenerator
- {
- private const string MonoTestRootAgency = "<RSAKeyValue><Modulus>v/4nALBxCE+9JgEC0LnDUvKh6e96PwTpN4Rj+vWnqKT7IAp1iK/JjuqvAg6DQ2vTfv0dTlqffmHH51OyioprcT5nzxcSTsZb/9jcHScG0s3/FRIWnXeLk/fgm7mSYhjUaHNI0m1/NTTktipicjKxo71hGIg9qucCWnDum+Krh/k=</Modulus><Exponent>AQAB</Exponent><P>9jbKxMXEruW2CfZrzhxtull4O8P47+mNsEL+9gf9QsRO1jJ77C+jmzfU6zbzjf8+ViK+q62tCMdC1ZzulwdpXQ==</P><Q>x5+p198l1PkK0Ga2mRh0SIYSykENpY2aLXoyZD/iUpKYAvATm0/wvKNrE4dKJyPCA+y3hfTdgVag+SP9avvDTQ==</Q><DP>ISSjCvXsUfbOGG05eddN1gXxL2pj+jegQRfjpk7RAsnWKvNExzhqd5x+ZuNQyc6QH5wxun54inP4RTUI0P/IaQ==</DP><DQ>R815VQmR3RIbPqzDXzv5j6CSH6fYlcTiQRtkBsUnzhWmkd/y3XmamO+a8zJFjOCCx9CcjpVuGziivBqi65lVPQ==</DQ><InverseQ>iYiu0KwMWI/dyqN3RJYUzuuLj02/oTD1pYpwo2rvNCXU1Q5VscOeu2DpNg1gWqI+1RrRCsEoaTNzXB1xtKNlSw==</InverseQ><D>nIfh1LYF8fjRBgMdAH/zt9UKHWiaCnc+jXzq5tkR8HVSKTVdzitD8bl1JgAfFQD8VjSXiCJqluexy/B5SGrCXQ49c78NIQj0hD+J13Y8/E0fUbW1QYbhj6Ff7oHyhaYe1WOQfkp2t/h+llHOdt1HRf7bt7dUknYp7m8bQKGxoYE=</D></RSAKeyValue>";
-
- public static void CreateSelfSignCertificatePfx(
- string fileName,
- string hostname,
- string password,
- ILogger logger)
- {
- if (string.IsNullOrWhiteSpace(fileName))
- {
- throw new ArgumentNullException("fileName");
- }
-
- byte[] sn = Guid.NewGuid().ToByteArray();
- string subject = string.Format("CN={0}", hostname);
- string issuer = subject;
- DateTime notBefore = DateTime.Now.AddDays(-2);
- DateTime notAfter = DateTime.Now.AddYears(10);
-
- RSA issuerKey = RSA.Create();
-#if NET46
- issuerKey.FromXmlString(MonoTestRootAgency);
-#else
- RSACryptoServiceProviderExtensions.FromXmlString(issuerKey, MonoTestRootAgency);
-#endif
- RSA subjectKey = RSA.Create();
-
- // serial number MUST be positive
- if ((sn[0] & 0x80) == 0x80)
- sn[0] -= 0x80;
-
- issuer = subject;
- issuerKey = subjectKey;
-
- X509CertificateBuilder cb = new X509CertificateBuilder(3);
- cb.SerialNumber = sn;
- cb.IssuerName = issuer;
- cb.NotBefore = notBefore;
- cb.NotAfter = notAfter;
- cb.SubjectName = subject;
- cb.SubjectPublicKey = subjectKey;
-
- // signature
- cb.Hash = "SHA256";
- byte[] rawcert = cb.Sign(issuerKey);
-
- PKCS12 p12 = new PKCS12();
-
-
- ArrayList list = new ArrayList();
- // we use a fixed array to avoid endianess issues
- // (in case some tools requires the ID to be 1).
- list.Add(new byte[4] { 1, 0, 0, 0 });
- Hashtable attributes = new Hashtable(1);
- attributes.Add(PKCS9.localKeyId, list);
-
- p12.AddCertificate(new X509Certificate(rawcert), attributes);
- p12.Password = password;
-
- p12.AddPkcs8ShroudedKeyBag(subjectKey, attributes);
- p12.SaveToFile(fileName);
- }
- }
-
- public static class RSACryptoServiceProviderExtensions
- {
- public static void FromXmlString(RSA rsa, string xmlString)
- {
- RSAParameters parameters = new RSAParameters();
-
- XmlDocument xmlDoc = new XmlDocument();
- xmlDoc.LoadXml(xmlString);
-
- if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
- {
- foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
- {
- switch (node.Name)
- {
- case "Modulus": parameters.Modulus = Convert.FromBase64String(node.InnerText); break;
- case "Exponent": parameters.Exponent = Convert.FromBase64String(node.InnerText); break;
- case "P": parameters.P = Convert.FromBase64String(node.InnerText); break;
- case "Q": parameters.Q = Convert.FromBase64String(node.InnerText); break;
- case "DP": parameters.DP = Convert.FromBase64String(node.InnerText); break;
- case "DQ": parameters.DQ = Convert.FromBase64String(node.InnerText); break;
- case "InverseQ": parameters.InverseQ = Convert.FromBase64String(node.InnerText); break;
- case "D": parameters.D = Convert.FromBase64String(node.InnerText); break;
- }
- }
- }
- else
- {
- throw new Exception("Invalid XML RSA key.");
- }
-
- rsa.ImportParameters(parameters);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/CryptoConvert.cs b/Emby.Server.Implementations/Cryptography/CryptoConvert.cs
deleted file mode 100644
index 70a91bfff..000000000
--- a/Emby.Server.Implementations/Cryptography/CryptoConvert.cs
+++ /dev/null
@@ -1,745 +0,0 @@
-//
-// CryptoConvert.cs - Crypto Convertion Routines
-//
-// Author:
-// Sebastien Pouliot <sebastien@ximian.com>
-//
-// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Globalization;
-using System.Security.Cryptography;
-using System.Text;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- public sealed class CryptoConvert {
-
- private CryptoConvert ()
- {
- }
-
- static private int ToInt32LE (byte [] bytes, int offset)
- {
- return (bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset];
- }
-
- static private uint ToUInt32LE (byte [] bytes, int offset)
- {
- return (uint)((bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]);
- }
-
- static private byte [] GetBytesLE (int val)
- {
- return new byte [] {
- (byte) (val & 0xff),
- (byte) ((val >> 8) & 0xff),
- (byte) ((val >> 16) & 0xff),
- (byte) ((val >> 24) & 0xff)
- };
- }
-
- static private byte[] Trim (byte[] array)
- {
- for (int i=0; i < array.Length; i++) {
- if (array [i] != 0x00) {
- byte[] result = new byte [array.Length - i];
- Buffer.BlockCopy (array, i, result, 0, result.Length);
- return result;
- }
- }
- return null;
- }
-
- // convert the key from PRIVATEKEYBLOB to RSA
- // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/Security/private_key_blobs.asp
- // e.g. SNK files, PVK files
- static public RSA FromCapiPrivateKeyBlob (byte[] blob)
- {
- return FromCapiPrivateKeyBlob (blob, 0);
- }
-
- static public RSA FromCapiPrivateKeyBlob (byte[] blob, int offset)
- {
- if (blob == null)
- throw new ArgumentNullException ("blob");
- if (offset >= blob.Length)
- throw new ArgumentException ("blob is too small.");
-
- RSAParameters rsap = new RSAParameters ();
- try {
- if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
- (blob [offset+1] != 0x02) || // Version (0x02)
- (blob [offset+2] != 0x00) || // Reserved (word)
- (blob [offset+3] != 0x00) ||
- (ToUInt32LE (blob, offset+8) != 0x32415352)) // DWORD magic = RSA2
- throw new CryptographicException ("Invalid blob header");
-
- // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
- // int algId = ToInt32LE (blob, offset+4);
-
- // DWORD bitlen
- int bitLen = ToInt32LE (blob, offset+12);
-
- // DWORD public exponent
- byte[] exp = new byte [4];
- Buffer.BlockCopy (blob, offset+16, exp, 0, 4);
- Array.Reverse (exp);
- rsap.Exponent = Trim (exp);
-
- int pos = offset+20;
- // BYTE modulus[rsapubkey.bitlen/8];
- int byteLen = (bitLen >> 3);
- rsap.Modulus = new byte [byteLen];
- Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
- Array.Reverse (rsap.Modulus);
- pos += byteLen;
-
- // BYTE prime1[rsapubkey.bitlen/16];
- int byteHalfLen = (byteLen >> 1);
- rsap.P = new byte [byteHalfLen];
- Buffer.BlockCopy (blob, pos, rsap.P, 0, byteHalfLen);
- Array.Reverse (rsap.P);
- pos += byteHalfLen;
-
- // BYTE prime2[rsapubkey.bitlen/16];
- rsap.Q = new byte [byteHalfLen];
- Buffer.BlockCopy (blob, pos, rsap.Q, 0, byteHalfLen);
- Array.Reverse (rsap.Q);
- pos += byteHalfLen;
-
- // BYTE exponent1[rsapubkey.bitlen/16];
- rsap.DP = new byte [byteHalfLen];
- Buffer.BlockCopy (blob, pos, rsap.DP, 0, byteHalfLen);
- Array.Reverse (rsap.DP);
- pos += byteHalfLen;
-
- // BYTE exponent2[rsapubkey.bitlen/16];
- rsap.DQ = new byte [byteHalfLen];
- Buffer.BlockCopy (blob, pos, rsap.DQ, 0, byteHalfLen);
- Array.Reverse (rsap.DQ);
- pos += byteHalfLen;
-
- // BYTE coefficient[rsapubkey.bitlen/16];
- rsap.InverseQ = new byte [byteHalfLen];
- Buffer.BlockCopy (blob, pos, rsap.InverseQ, 0, byteHalfLen);
- Array.Reverse (rsap.InverseQ);
- pos += byteHalfLen;
-
- // ok, this is hackish but CryptoAPI support it so...
- // note: only works because CRT is used by default
- // http://bugzilla.ximian.com/show_bug.cgi?id=57941
- rsap.D = new byte [byteLen]; // must be allocated
- if (pos + byteLen + offset <= blob.Length) {
- // BYTE privateExponent[rsapubkey.bitlen/8];
- Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen);
- Array.Reverse (rsap.D);
- }
- }
- catch (Exception e) {
- throw new CryptographicException ("Invalid blob.", e);
- }
-
- RSA rsa = null;
- try
- {
- rsa = RSA.Create();
- rsa.ImportParameters(rsap);
- }
- catch (CryptographicException ce)
- {
- // this may cause problem when this code is run under
- // the SYSTEM identity on Windows (e.g. ASP.NET). See
- // http://bugzilla.ximian.com/show_bug.cgi?id=77559
- try
- {
- CspParameters csp = new CspParameters();
- csp.Flags = CspProviderFlags.UseMachineKeyStore;
- rsa = new RSACryptoServiceProvider(csp);
- rsa.ImportParameters(rsap);
- }
- catch
- {
- // rethrow original, not the later, exception if this fails
- throw ce;
- }
- }
- return rsa;
- }
-
- static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob)
- {
- return FromCapiPrivateKeyBlobDSA (blob, 0);
- }
-
- static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob, int offset)
- {
- if (blob == null)
- throw new ArgumentNullException ("blob");
- if (offset >= blob.Length)
- throw new ArgumentException ("blob is too small.");
-
- DSAParameters dsap = new DSAParameters ();
- try {
- if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
- (blob [offset + 1] != 0x02) || // Version (0x02)
- (blob [offset + 2] != 0x00) || // Reserved (word)
- (blob [offset + 3] != 0x00) ||
- (ToUInt32LE (blob, offset + 8) != 0x32535344)) // DWORD magic
- throw new CryptographicException ("Invalid blob header");
-
- int bitlen = ToInt32LE (blob, offset + 12);
- int bytelen = bitlen >> 3;
- int pos = offset + 16;
-
- dsap.P = new byte [bytelen];
- Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
- Array.Reverse (dsap.P);
- pos += bytelen;
-
- dsap.Q = new byte [20];
- Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
- Array.Reverse (dsap.Q);
- pos += 20;
-
- dsap.G = new byte [bytelen];
- Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
- Array.Reverse (dsap.G);
- pos += bytelen;
-
- dsap.X = new byte [20];
- Buffer.BlockCopy (blob, pos, dsap.X, 0, 20);
- Array.Reverse (dsap.X);
- pos += 20;
-
- dsap.Counter = ToInt32LE (blob, pos);
- pos += 4;
-
- dsap.Seed = new byte [20];
- Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
- Array.Reverse (dsap.Seed);
- pos += 20;
- }
- catch (Exception e) {
- throw new CryptographicException ("Invalid blob.", e);
- }
-
- DSA dsa = null;
- try
- {
- dsa = (DSA)DSA.Create();
- dsa.ImportParameters(dsap);
- }
- catch (CryptographicException ce)
- {
- // this may cause problem when this code is run under
- // the SYSTEM identity on Windows (e.g. ASP.NET). See
- // http://bugzilla.ximian.com/show_bug.cgi?id=77559
- try
- {
- CspParameters csp = new CspParameters();
- csp.Flags = CspProviderFlags.UseMachineKeyStore;
- dsa = new DSACryptoServiceProvider(csp);
- dsa.ImportParameters(dsap);
- }
- catch
- {
- // rethrow original, not the later, exception if this fails
- throw ce;
- }
- }
- return dsa;
- }
-
- static public byte[] ToCapiPrivateKeyBlob (RSA rsa)
- {
- RSAParameters p = rsa.ExportParameters (true);
- int keyLength = p.Modulus.Length; // in bytes
- byte[] blob = new byte [20 + (keyLength << 2) + (keyLength >> 1)];
-
- blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07)
- blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
- // [2], [3] // RESERVED - Always 0
- blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
- blob [8] = 0x52; // Magic - RSA2 (ASCII in hex)
- blob [9] = 0x53;
- blob [10] = 0x41;
- blob [11] = 0x32;
-
- byte[] bitlen = GetBytesLE (keyLength << 3);
- blob [12] = bitlen [0]; // bitlen
- blob [13] = bitlen [1];
- blob [14] = bitlen [2];
- blob [15] = bitlen [3];
-
- // public exponent (DWORD)
- int pos = 16;
- int n = p.Exponent.Length;
- while (n > 0)
- blob [pos++] = p.Exponent [--n];
- // modulus
- pos = 20;
- byte[] part = p.Modulus;
- int len = part.Length;
- Array.Reverse (part, 0, len);
- Buffer.BlockCopy (part, 0, blob, pos, len);
- pos += len;
- // private key
- part = p.P;
- len = part.Length;
- Array.Reverse (part, 0, len);
- Buffer.BlockCopy (part, 0, blob, pos, len);
- pos += len;
-
- part = p.Q;
- len = part.Length;
- Array.Reverse (part, 0, len);
- Buffer.BlockCopy (part, 0, blob, pos, len);
- pos += len;
-
- part = p.DP;
- len = part.Length;
- Array.Reverse (part, 0, len);
- Buffer.BlockCopy (part, 0, blob, pos, len);
- pos += len;
-
- part = p.DQ;
- len = part.Length;
- Array.Reverse (part, 0, len);
- Buffer.BlockCopy (part, 0, blob, pos, len);
- pos += len;
-
- part = p.InverseQ;
- len = part.Length;
- Array.Reverse (part, 0, len);
- Buffer.BlockCopy (part, 0, blob, pos, len);
- pos += len;
-
- part = p.D;
- len = part.Length;
- Array.Reverse (part, 0, len);
- Buffer.BlockCopy (part, 0, blob, pos, len);
-
- return blob;
- }
-
- static public byte[] ToCapiPrivateKeyBlob (DSA dsa)
- {
- DSAParameters p = dsa.ExportParameters (true);
- int keyLength = p.P.Length; // in bytes
-
- // header + P + Q + G + X + count + seed
- byte[] blob = new byte [16 + keyLength + 20 + keyLength + 20 + 4 + 20];
-
- blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07)
- blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
- // [2], [3] // RESERVED - Always 0
- blob [5] = 0x22; // ALGID
- blob [8] = 0x44; // Magic
- blob [9] = 0x53;
- blob [10] = 0x53;
- blob [11] = 0x32;
-
- byte[] bitlen = GetBytesLE (keyLength << 3);
- blob [12] = bitlen [0];
- blob [13] = bitlen [1];
- blob [14] = bitlen [2];
- blob [15] = bitlen [3];
-
- int pos = 16;
- byte[] part = p.P;
- Array.Reverse (part);
- Buffer.BlockCopy (part, 0, blob, pos, keyLength);
- pos += keyLength;
-
- part = p.Q;
- Array.Reverse (part);
- Buffer.BlockCopy (part, 0, blob, pos, 20);
- pos += 20;
-
- part = p.G;
- Array.Reverse (part);
- Buffer.BlockCopy (part, 0, blob, pos, keyLength);
- pos += keyLength;
-
- part = p.X;
- Array.Reverse (part);
- Buffer.BlockCopy (part, 0, blob, pos, 20);
- pos += 20;
-
- Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
- pos += 4;
-
- part = p.Seed;
- Array.Reverse (part);
- Buffer.BlockCopy (part, 0, blob, pos, 20);
-
- return blob;
- }
-
- static public RSA FromCapiPublicKeyBlob (byte[] blob)
- {
- return FromCapiPublicKeyBlob (blob, 0);
- }
-
- static public RSA FromCapiPublicKeyBlob (byte[] blob, int offset)
- {
- if (blob == null)
- throw new ArgumentNullException ("blob");
- if (offset >= blob.Length)
- throw new ArgumentException ("blob is too small.");
-
- try {
- if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06)
- (blob [offset+1] != 0x02) || // Version (0x02)
- (blob [offset+2] != 0x00) || // Reserved (word)
- (blob [offset+3] != 0x00) ||
- (ToUInt32LE (blob, offset+8) != 0x31415352)) // DWORD magic = RSA1
- throw new CryptographicException ("Invalid blob header");
-
- // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
- // int algId = ToInt32LE (blob, offset+4);
-
- // DWORD bitlen
- int bitLen = ToInt32LE (blob, offset+12);
-
- // DWORD public exponent
- RSAParameters rsap = new RSAParameters ();
- rsap.Exponent = new byte [3];
- rsap.Exponent [0] = blob [offset+18];
- rsap.Exponent [1] = blob [offset+17];
- rsap.Exponent [2] = blob [offset+16];
-
- int pos = offset+20;
- // BYTE modulus[rsapubkey.bitlen/8];
- int byteLen = (bitLen >> 3);
- rsap.Modulus = new byte [byteLen];
- Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
- Array.Reverse (rsap.Modulus);
- RSA rsa = null;
- try
- {
- rsa = RSA.Create();
- rsa.ImportParameters(rsap);
- }
- catch (CryptographicException)
- {
- // this may cause problem when this code is run under
- // the SYSTEM identity on Windows (e.g. ASP.NET). See
- // http://bugzilla.ximian.com/show_bug.cgi?id=77559
- CspParameters csp = new CspParameters();
- csp.Flags = CspProviderFlags.UseMachineKeyStore;
- rsa = new RSACryptoServiceProvider(csp);
- rsa.ImportParameters(rsap);
- }
- return rsa;
- }
- catch (Exception e) {
- throw new CryptographicException ("Invalid blob.", e);
- }
- }
-
- static public DSA FromCapiPublicKeyBlobDSA (byte[] blob)
- {
- return FromCapiPublicKeyBlobDSA (blob, 0);
- }
-
- static public DSA FromCapiPublicKeyBlobDSA (byte[] blob, int offset)
- {
- if (blob == null)
- throw new ArgumentNullException ("blob");
- if (offset >= blob.Length)
- throw new ArgumentException ("blob is too small.");
-
- try {
- if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06)
- (blob [offset + 1] != 0x02) || // Version (0x02)
- (blob [offset + 2] != 0x00) || // Reserved (word)
- (blob [offset + 3] != 0x00) ||
- (ToUInt32LE (blob, offset + 8) != 0x31535344)) // DWORD magic
- throw new CryptographicException ("Invalid blob header");
-
- int bitlen = ToInt32LE (blob, offset + 12);
- DSAParameters dsap = new DSAParameters ();
- int bytelen = bitlen >> 3;
- int pos = offset + 16;
-
- dsap.P = new byte [bytelen];
- Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
- Array.Reverse (dsap.P);
- pos += bytelen;
-
- dsap.Q = new byte [20];
- Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
- Array.Reverse (dsap.Q);
- pos += 20;
-
- dsap.G = new byte [bytelen];
- Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
- Array.Reverse (dsap.G);
- pos += bytelen;
-
- dsap.Y = new byte [bytelen];
- Buffer.BlockCopy (blob, pos, dsap.Y, 0, bytelen);
- Array.Reverse (dsap.Y);
- pos += bytelen;
-
- dsap.Counter = ToInt32LE (blob, pos);
- pos += 4;
-
- dsap.Seed = new byte [20];
- Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
- Array.Reverse (dsap.Seed);
- pos += 20;
-
- DSA dsa = (DSA)DSA.Create ();
- dsa.ImportParameters (dsap);
- return dsa;
- }
- catch (Exception e) {
- throw new CryptographicException ("Invalid blob.", e);
- }
- }
-
- static public byte[] ToCapiPublicKeyBlob (RSA rsa)
- {
- RSAParameters p = rsa.ExportParameters (false);
- int keyLength = p.Modulus.Length; // in bytes
- byte[] blob = new byte [20 + keyLength];
-
- blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06)
- blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
- // [2], [3] // RESERVED - Always 0
- blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
- blob [8] = 0x52; // Magic - RSA1 (ASCII in hex)
- blob [9] = 0x53;
- blob [10] = 0x41;
- blob [11] = 0x31;
-
- byte[] bitlen = GetBytesLE (keyLength << 3);
- blob [12] = bitlen [0]; // bitlen
- blob [13] = bitlen [1];
- blob [14] = bitlen [2];
- blob [15] = bitlen [3];
-
- // public exponent (DWORD)
- int pos = 16;
- int n = p.Exponent.Length;
- while (n > 0)
- blob [pos++] = p.Exponent [--n];
- // modulus
- pos = 20;
- byte[] part = p.Modulus;
- int len = part.Length;
- Array.Reverse (part, 0, len);
- Buffer.BlockCopy (part, 0, blob, pos, len);
- pos += len;
- return blob;
- }
-
- static public byte[] ToCapiPublicKeyBlob (DSA dsa)
- {
- DSAParameters p = dsa.ExportParameters (false);
- int keyLength = p.P.Length; // in bytes
-
- // header + P + Q + G + Y + count + seed
- byte[] blob = new byte [16 + keyLength + 20 + keyLength + keyLength + 4 + 20];
-
- blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06)
- blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
- // [2], [3] // RESERVED - Always 0
- blob [5] = 0x22; // ALGID
- blob [8] = 0x44; // Magic
- blob [9] = 0x53;
- blob [10] = 0x53;
- blob [11] = 0x31;
-
- byte[] bitlen = GetBytesLE (keyLength << 3);
- blob [12] = bitlen [0];
- blob [13] = bitlen [1];
- blob [14] = bitlen [2];
- blob [15] = bitlen [3];
-
- int pos = 16;
- byte[] part;
-
- part = p.P;
- Array.Reverse (part);
- Buffer.BlockCopy (part, 0, blob, pos, keyLength);
- pos += keyLength;
-
- part = p.Q;
- Array.Reverse (part);
- Buffer.BlockCopy (part, 0, blob, pos, 20);
- pos += 20;
-
- part = p.G;
- Array.Reverse (part);
- Buffer.BlockCopy (part, 0, blob, pos, keyLength);
- pos += keyLength;
-
- part = p.Y;
- Array.Reverse (part);
- Buffer.BlockCopy (part, 0, blob, pos, keyLength);
- pos += keyLength;
-
- Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
- pos += 4;
-
- part = p.Seed;
- Array.Reverse (part);
- Buffer.BlockCopy (part, 0, blob, pos, 20);
-
- return blob;
- }
-
- // PRIVATEKEYBLOB
- // PUBLICKEYBLOB
- static public RSA FromCapiKeyBlob (byte[] blob)
- {
- return FromCapiKeyBlob (blob, 0);
- }
-
- static public RSA FromCapiKeyBlob (byte[] blob, int offset)
- {
- if (blob == null)
- throw new ArgumentNullException ("blob");
- if (offset >= blob.Length)
- throw new ArgumentException ("blob is too small.");
-
- switch (blob [offset]) {
- case 0x00:
- // this could be a public key inside an header
- // like "sn -e" would produce
- if (blob [offset + 12] == 0x06) {
- return FromCapiPublicKeyBlob (blob, offset + 12);
- }
- break;
- case 0x06:
- return FromCapiPublicKeyBlob (blob, offset);
- case 0x07:
- return FromCapiPrivateKeyBlob (blob, offset);
- }
- throw new CryptographicException ("Unknown blob format.");
- }
-
- static public DSA FromCapiKeyBlobDSA (byte[] blob)
- {
- return FromCapiKeyBlobDSA (blob, 0);
- }
-
- static public DSA FromCapiKeyBlobDSA (byte[] blob, int offset)
- {
- if (blob == null)
- throw new ArgumentNullException ("blob");
- if (offset >= blob.Length)
- throw new ArgumentException ("blob is too small.");
-
- switch (blob [offset]) {
- case 0x06:
- return FromCapiPublicKeyBlobDSA (blob, offset);
- case 0x07:
- return FromCapiPrivateKeyBlobDSA (blob, offset);
- }
- throw new CryptographicException ("Unknown blob format.");
- }
-
- static public byte[] ToCapiKeyBlob (AsymmetricAlgorithm keypair, bool includePrivateKey)
- {
- if (keypair == null)
- throw new ArgumentNullException ("keypair");
-
- // check between RSA and DSA (and potentially others like DH)
- if (keypair is RSA)
- return ToCapiKeyBlob ((RSA)keypair, includePrivateKey);
- else if (keypair is DSA)
- return ToCapiKeyBlob ((DSA)keypair, includePrivateKey);
- else
- return null; // TODO
- }
-
- static public byte[] ToCapiKeyBlob (RSA rsa, bool includePrivateKey)
- {
- if (rsa == null)
- throw new ArgumentNullException ("rsa");
-
- if (includePrivateKey)
- return ToCapiPrivateKeyBlob (rsa);
- else
- return ToCapiPublicKeyBlob (rsa);
- }
-
- static public byte[] ToCapiKeyBlob (DSA dsa, bool includePrivateKey)
- {
- if (dsa == null)
- throw new ArgumentNullException ("dsa");
-
- if (includePrivateKey)
- return ToCapiPrivateKeyBlob (dsa);
- else
- return ToCapiPublicKeyBlob (dsa);
- }
-
- static public string ToHex (byte[] input)
- {
- if (input == null)
- return null;
-
- StringBuilder sb = new StringBuilder (input.Length * 2);
- foreach (byte b in input) {
- sb.Append (b.ToString ("X2", CultureInfo.InvariantCulture));
- }
- return sb.ToString ();
- }
-
- static private byte FromHexChar (char c)
- {
- if ((c >= 'a') && (c <= 'f'))
- return (byte) (c - 'a' + 10);
- if ((c >= 'A') && (c <= 'F'))
- return (byte) (c - 'A' + 10);
- if ((c >= '0') && (c <= '9'))
- return (byte) (c - '0');
- throw new ArgumentException ("invalid hex char");
- }
-
- static public byte[] FromHex (string hex)
- {
- if (hex == null)
- return null;
- if ((hex.Length & 0x1) == 0x1)
- throw new ArgumentException ("Length must be a multiple of 2");
-
- byte[] result = new byte [hex.Length >> 1];
- int n = 0;
- int i = 0;
- while (n < result.Length) {
- result [n] = (byte) (FromHexChar (hex [i++]) << 4);
- result [n++] += FromHexChar (hex [i++]);
- }
- return result;
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/PKCS1.cs b/Emby.Server.Implementations/Cryptography/PKCS1.cs
deleted file mode 100644
index 24c0708c5..000000000
--- a/Emby.Server.Implementations/Cryptography/PKCS1.cs
+++ /dev/null
@@ -1,491 +0,0 @@
-//
-// PKCS1.cs - Implements PKCS#1 primitives.
-//
-// Author:
-// Sebastien Pouliot <sebastien@xamarin.com>
-//
-// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
-// Copyright 2013 Xamarin Inc. (http://www.xamarin.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Security.Cryptography;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- // References:
- // a. PKCS#1: RSA Cryptography Standard
- // http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/index.html
-
- public sealed class PKCS1 {
-
- private PKCS1 ()
- {
- }
-
- private static bool Compare (byte[] array1, byte[] array2)
- {
- bool result = (array1.Length == array2.Length);
- if (result) {
- for (int i=0; i < array1.Length; i++)
- if (array1[i] != array2[i])
- return false;
- }
- return result;
- }
-
- private static byte[] xor (byte[] array1, byte[] array2)
- {
- byte[] result = new byte [array1.Length];
- for (int i=0; i < result.Length; i++)
- result[i] = (byte) (array1[i] ^ array2[i]);
- return result;
- }
-
- private static byte[] emptySHA1 = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 };
- private static byte[] emptySHA256 = { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 };
- private static byte[] emptySHA384 = { 0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a, 0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda, 0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b };
- private static byte[] emptySHA512 = { 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e };
-
- private static byte[] GetEmptyHash (HashAlgorithm hash)
- {
- if (hash is SHA1)
- return emptySHA1;
- else if (hash is SHA256)
- return emptySHA256;
- else if (hash is SHA384)
- return emptySHA384;
- else if (hash is SHA512)
- return emptySHA512;
- else
- return hash.ComputeHash ((byte[])null);
- }
-
- // PKCS #1 v.2.1, Section 4.1
- // I2OSP converts a non-negative integer to an octet string of a specified length.
- public static byte[] I2OSP (int x, int size)
- {
- byte[] array = BitConverterLE.GetBytes (x);
- Array.Reverse (array, 0, array.Length);
- return I2OSP (array, size);
- }
-
- public static byte[] I2OSP (byte[] x, int size)
- {
- byte[] result = new byte [size];
- Buffer.BlockCopy (x, 0, result, (result.Length - x.Length), x.Length);
- return result;
- }
-
- // PKCS #1 v.2.1, Section 4.2
- // OS2IP converts an octet string to a nonnegative integer.
- public static byte[] OS2IP (byte[] x)
- {
- int i = 0;
- while ((x [i++] == 0x00) && (i < x.Length)) {
- // confuse compiler into reporting a warning with {}
- }
- i--;
- if (i > 0) {
- byte[] result = new byte [x.Length - i];
- Buffer.BlockCopy (x, i, result, 0, result.Length);
- return result;
- }
- else
- return x;
- }
-
- // PKCS #1 v.2.1, Section 5.1.1
- public static byte[] RSAEP (RSA rsa, byte[] m)
- {
- // c = m^e mod n
- return rsa.EncryptValue (m);
- }
-
- // PKCS #1 v.2.1, Section 5.1.2
- public static byte[] RSADP (RSA rsa, byte[] c)
- {
- // m = c^d mod n
- // Decrypt value may apply CRT optimizations
- return rsa.DecryptValue (c);
- }
-
- // PKCS #1 v.2.1, Section 5.2.1
- public static byte[] RSASP1 (RSA rsa, byte[] m)
- {
- // first form: s = m^d mod n
- // Decrypt value may apply CRT optimizations
- return rsa.DecryptValue (m);
- }
-
- // PKCS #1 v.2.1, Section 5.2.2
- public static byte[] RSAVP1 (RSA rsa, byte[] s)
- {
- // m = s^e mod n
- return rsa.EncryptValue (s);
- }
-
- // PKCS #1 v.2.1, Section 7.1.1
- // RSAES-OAEP-ENCRYPT ((n, e), M, L)
- public static byte[] Encrypt_OAEP (RSA rsa, HashAlgorithm hash, RandomNumberGenerator rng, byte[] M)
- {
- int size = rsa.KeySize / 8;
- int hLen = hash.HashSize / 8;
- if (M.Length > size - 2 * hLen - 2)
- throw new CryptographicException ("message too long");
- // empty label L SHA1 hash
- byte[] lHash = GetEmptyHash (hash);
- int PSLength = (size - M.Length - 2 * hLen - 2);
- // DB = lHash || PS || 0x01 || M
- byte[] DB = new byte [lHash.Length + PSLength + 1 + M.Length];
- Buffer.BlockCopy (lHash, 0, DB, 0, lHash.Length);
- DB [(lHash.Length + PSLength)] = 0x01;
- Buffer.BlockCopy (M, 0, DB, (DB.Length - M.Length), M.Length);
-
- byte[] seed = new byte [hLen];
- rng.GetBytes (seed);
-
- byte[] dbMask = MGF1 (hash, seed, size - hLen - 1);
- byte[] maskedDB = xor (DB, dbMask);
- byte[] seedMask = MGF1 (hash, maskedDB, hLen);
- byte[] maskedSeed = xor (seed, seedMask);
- // EM = 0x00 || maskedSeed || maskedDB
- byte[] EM = new byte [maskedSeed.Length + maskedDB.Length + 1];
- Buffer.BlockCopy (maskedSeed, 0, EM, 1, maskedSeed.Length);
- Buffer.BlockCopy (maskedDB, 0, EM, maskedSeed.Length + 1, maskedDB.Length);
-
- byte[] m = OS2IP (EM);
- byte[] c = RSAEP (rsa, m);
- return I2OSP (c, size);
- }
-
- // PKCS #1 v.2.1, Section 7.1.2
- // RSAES-OAEP-DECRYPT (K, C, L)
- public static byte[] Decrypt_OAEP (RSA rsa, HashAlgorithm hash, byte[] C)
- {
- int size = rsa.KeySize / 8;
- int hLen = hash.HashSize / 8;
- if ((size < (2 * hLen + 2)) || (C.Length != size))
- throw new CryptographicException ("decryption error");
-
- byte[] c = OS2IP (C);
- byte[] m = RSADP (rsa, c);
- byte[] EM = I2OSP (m, size);
-
- // split EM = Y || maskedSeed || maskedDB
- byte[] maskedSeed = new byte [hLen];
- Buffer.BlockCopy (EM, 1, maskedSeed, 0, maskedSeed.Length);
- byte[] maskedDB = new byte [size - hLen - 1];
- Buffer.BlockCopy (EM, (EM.Length - maskedDB.Length), maskedDB, 0, maskedDB.Length);
-
- byte[] seedMask = MGF1 (hash, maskedDB, hLen);
- byte[] seed = xor (maskedSeed, seedMask);
- byte[] dbMask = MGF1 (hash, seed, size - hLen - 1);
- byte[] DB = xor (maskedDB, dbMask);
-
- byte[] lHash = GetEmptyHash (hash);
- // split DB = lHash' || PS || 0x01 || M
- byte[] dbHash = new byte [lHash.Length];
- Buffer.BlockCopy (DB, 0, dbHash, 0, dbHash.Length);
- bool h = Compare (lHash, dbHash);
-
- // find separator 0x01
- int nPos = lHash.Length;
- while (DB[nPos] == 0)
- nPos++;
-
- int Msize = DB.Length - nPos - 1;
- byte[] M = new byte [Msize];
- Buffer.BlockCopy (DB, (nPos + 1), M, 0, Msize);
-
- // we could have returned EM[0] sooner but would be helping a timing attack
- if ((EM[0] != 0) || (!h) || (DB[nPos] != 0x01))
- return null;
- return M;
- }
-
- // PKCS #1 v.2.1, Section 7.2.1
- // RSAES-PKCS1-V1_5-ENCRYPT ((n, e), M)
- public static byte[] Encrypt_v15 (RSA rsa, RandomNumberGenerator rng, byte[] M)
- {
- int size = rsa.KeySize / 8;
- if (M.Length > size - 11)
- throw new CryptographicException ("message too long");
- int PSLength = System.Math.Max (8, (size - M.Length - 3));
- byte[] PS = new byte [PSLength];
- rng.GetNonZeroBytes (PS);
- byte[] EM = new byte [size];
- EM [1] = 0x02;
- Buffer.BlockCopy (PS, 0, EM, 2, PSLength);
- Buffer.BlockCopy (M, 0, EM, (size - M.Length), M.Length);
-
- byte[] m = OS2IP (EM);
- byte[] c = RSAEP (rsa, m);
- byte[] C = I2OSP (c, size);
- return C;
- }
-
- // PKCS #1 v.2.1, Section 7.2.2
- // RSAES-PKCS1-V1_5-DECRYPT (K, C)
- public static byte[] Decrypt_v15 (RSA rsa, byte[] C)
- {
- int size = rsa.KeySize >> 3; // div by 8
- if ((size < 11) || (C.Length > size))
- throw new CryptographicException ("decryption error");
- byte[] c = OS2IP (C);
- byte[] m = RSADP (rsa, c);
- byte[] EM = I2OSP (m, size);
-
- if ((EM [0] != 0x00) || (EM [1] != 0x02))
- return null;
-
- int mPos = 10;
- // PS is a minimum of 8 bytes + 2 bytes for header
- while ((EM [mPos] != 0x00) && (mPos < EM.Length))
- mPos++;
- if (EM [mPos] != 0x00)
- return null;
- mPos++;
- byte[] M = new byte [EM.Length - mPos];
- Buffer.BlockCopy (EM, mPos, M, 0, M.Length);
- return M;
- }
-
- // PKCS #1 v.2.1, Section 8.2.1
- // RSASSA-PKCS1-V1_5-SIGN (K, M)
- public static byte[] Sign_v15 (RSA rsa, HashAlgorithm hash, byte[] hashValue)
- {
- int size = (rsa.KeySize >> 3); // div 8
- byte[] EM = Encode_v15 (hash, hashValue, size);
- byte[] m = OS2IP (EM);
- byte[] s = RSASP1 (rsa, m);
- byte[] S = I2OSP (s, size);
- return S;
- }
-
- internal static byte[] Sign_v15 (RSA rsa, string hashName, byte[] hashValue)
- {
- using (var hash = CreateFromName (hashName))
- return Sign_v15 (rsa, hash, hashValue);
- }
-
- // PKCS #1 v.2.1, Section 8.2.2
- // RSASSA-PKCS1-V1_5-VERIFY ((n, e), M, S)
- public static bool Verify_v15 (RSA rsa, HashAlgorithm hash, byte[] hashValue, byte[] signature)
- {
- return Verify_v15 (rsa, hash, hashValue, signature, false);
- }
-
- internal static bool Verify_v15 (RSA rsa, string hashName, byte[] hashValue, byte[] signature)
- {
- using (var hash = CreateFromName (hashName))
- return Verify_v15 (rsa, hash, hashValue, signature, false);
- }
-
- // DO NOT USE WITHOUT A VERY GOOD REASON
- public static bool Verify_v15 (RSA rsa, HashAlgorithm hash, byte [] hashValue, byte [] signature, bool tryNonStandardEncoding)
- {
- int size = (rsa.KeySize >> 3); // div 8
- byte[] s = OS2IP (signature);
- byte[] m = RSAVP1 (rsa, s);
- byte[] EM2 = I2OSP (m, size);
- byte[] EM = Encode_v15 (hash, hashValue, size);
- bool result = Compare (EM, EM2);
- if (result || !tryNonStandardEncoding)
- return result;
-
- // NOTE: some signatures don't include the hash OID (pretty lame but real)
- // and compatible with MS implementation. E.g. Verisign Authenticode Timestamps
-
- // we're making this "as safe as possible"
- if ((EM2 [0] != 0x00) || (EM2 [1] != 0x01))
- return false;
- int i;
- for (i = 2; i < EM2.Length - hashValue.Length - 1; i++) {
- if (EM2 [i] != 0xFF)
- return false;
- }
- if (EM2 [i++] != 0x00)
- return false;
-
- byte [] decryptedHash = new byte [hashValue.Length];
- Buffer.BlockCopy (EM2, i, decryptedHash, 0, decryptedHash.Length);
- return Compare (decryptedHash, hashValue);
- }
-
- // PKCS #1 v.2.1, Section 9.2
- // EMSA-PKCS1-v1_5-Encode
- public static byte[] Encode_v15 (HashAlgorithm hash, byte[] hashValue, int emLength)
- {
- if (hashValue.Length != (hash.HashSize >> 3))
- throw new CryptographicException ("bad hash length for " + hash.ToString ());
-
- // DigestInfo ::= SEQUENCE {
- // digestAlgorithm AlgorithmIdentifier,
- // digest OCTET STRING
- // }
-
- byte[] t = null;
-
- string oid = CryptoConfig.MapNameToOID (hash.ToString ());
- if (oid != null)
- {
- ASN1 digestAlgorithm = new ASN1 (0x30);
- digestAlgorithm.Add (new ASN1 (CryptoConfig.EncodeOID (oid)));
- digestAlgorithm.Add (new ASN1 (0x05)); // NULL
- ASN1 digest = new ASN1 (0x04, hashValue);
- ASN1 digestInfo = new ASN1 (0x30);
- digestInfo.Add (digestAlgorithm);
- digestInfo.Add (digest);
-
- t = digestInfo.GetBytes ();
- }
- else
- {
- // There are no valid OID, in this case t = hashValue
- // This is the case of the MD5SHA hash algorithm
- t = hashValue;
- }
-
- Buffer.BlockCopy (hashValue, 0, t, t.Length - hashValue.Length, hashValue.Length);
-
- int PSLength = System.Math.Max (8, emLength - t.Length - 3);
- // PS = PSLength of 0xff
-
- // EM = 0x00 | 0x01 | PS | 0x00 | T
- byte[] EM = new byte [PSLength + t.Length + 3];
- EM [1] = 0x01;
- for (int i=2; i < PSLength + 2; i++)
- EM[i] = 0xff;
- Buffer.BlockCopy (t, 0, EM, PSLength + 3, t.Length);
-
- return EM;
- }
-
- // PKCS #1 v.2.1, Section B.2.1
- public static byte[] MGF1 (HashAlgorithm hash, byte[] mgfSeed, int maskLen)
- {
- // 1. If maskLen > 2^32 hLen, output "mask too long" and stop.
- // easy - this is impossible by using a int (31bits) as parameter ;-)
- // BUT with a signed int we do have to check for negative values!
- if (maskLen < 0)
- throw new OverflowException();
-
- int mgfSeedLength = mgfSeed.Length;
- int hLen = (hash.HashSize >> 3); // from bits to bytes
- int iterations = (maskLen / hLen);
- if (maskLen % hLen != 0)
- iterations++;
- // 2. Let T be the empty octet string.
- byte[] T = new byte [iterations * hLen];
-
- byte[] toBeHashed = new byte [mgfSeedLength + 4];
- int pos = 0;
- // 3. For counter from 0 to \ceil (maskLen / hLen) - 1, do the following:
- for (int counter = 0; counter < iterations; counter++) {
- // a. Convert counter to an octet string C of length 4 octets
- byte[] C = I2OSP (counter, 4);
-
- // b. Concatenate the hash of the seed mgfSeed and C to the octet string T:
- // T = T || Hash (mgfSeed || C)
- Buffer.BlockCopy (mgfSeed, 0, toBeHashed, 0, mgfSeedLength);
- Buffer.BlockCopy (C, 0, toBeHashed, mgfSeedLength, 4);
- byte[] output = hash.ComputeHash (toBeHashed);
- Buffer.BlockCopy (output, 0, T, pos, hLen);
- pos += hLen;
- }
-
- // 4. Output the leading maskLen octets of T as the octet string mask.
- byte[] mask = new byte [maskLen];
- Buffer.BlockCopy (T, 0, mask, 0, maskLen);
- return mask;
- }
-
- static internal string HashNameFromOid (string oid, bool throwOnError = true)
- {
- switch (oid) {
- case "1.2.840.113549.1.1.2": // MD2 with RSA encryption
- return "MD2";
- case "1.2.840.113549.1.1.3": // MD4 with RSA encryption
- return "MD4";
- case "1.2.840.113549.1.1.4": // MD5 with RSA encryption
- return "MD5";
- case "1.2.840.113549.1.1.5": // SHA-1 with RSA Encryption
- case "1.3.14.3.2.29": // SHA1 with RSA signature
- case "1.2.840.10040.4.3": // SHA1-1 with DSA
- return "SHA1";
- case "1.2.840.113549.1.1.11": // SHA-256 with RSA Encryption
- return "SHA256";
- case "1.2.840.113549.1.1.12": // SHA-384 with RSA Encryption
- return "SHA384";
- case "1.2.840.113549.1.1.13": // SHA-512 with RSA Encryption
- return "SHA512";
- case "1.3.36.3.3.1.2":
- return "RIPEMD160";
- default:
- if (throwOnError)
- throw new CryptographicException ("Unsupported hash algorithm: " + oid);
- return null;
- }
- }
-
- static internal HashAlgorithm CreateFromOid (string oid)
- {
- return CreateFromName (HashNameFromOid (oid));
- }
-
- static internal HashAlgorithm CreateFromName (string name)
- {
-#if FULL_AOT_RUNTIME
- switch (name) {
- case "MD2":
- return MD2.Create ();
- case "MD4":
- return MD4.Create ();
- case "MD5":
- return MD5.Create ();
- case "SHA1":
- return SHA1.Create ();
- case "SHA256":
- return SHA256.Create ();
- case "SHA384":
- return SHA384.Create ();
- case "SHA512":
- return SHA512.Create ();
- case "RIPEMD160":
- return RIPEMD160.Create ();
- default:
- try {
- return (HashAlgorithm) Activator.CreateInstance (Type.GetType (name));
- }
- catch {
- throw new CryptographicException ("Unsupported hash algorithm: " + name);
- }
- }
-#else
- return HashAlgorithm.Create (name);
-#endif
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/PKCS12.cs b/Emby.Server.Implementations/Cryptography/PKCS12.cs
deleted file mode 100644
index 50f3776d9..000000000
--- a/Emby.Server.Implementations/Cryptography/PKCS12.cs
+++ /dev/null
@@ -1,1934 +0,0 @@
-//
-// PKCS12.cs: PKCS 12 - Personal Information Exchange Syntax
-//
-// Author:
-// Sebastien Pouliot <sebastien@xamarin.com>
-//
-// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004,2005,2006 Novell Inc. (http://www.novell.com)
-// Copyright 2013 Xamarin Inc. (http://www.xamarin.com)
-//
-// Key derivation translated from Bouncy Castle JCE (http://www.bouncycastle.org/)
-// See bouncycastle.txt for license.
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Collections;
-using System.IO;
-using System.Security.Cryptography;
-using System.Text;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- public class PKCS5 {
-
- public const string pbeWithMD2AndDESCBC = "1.2.840.113549.1.5.1";
- public const string pbeWithMD5AndDESCBC = "1.2.840.113549.1.5.3";
- public const string pbeWithMD2AndRC2CBC = "1.2.840.113549.1.5.4";
- public const string pbeWithMD5AndRC2CBC = "1.2.840.113549.1.5.6";
- public const string pbeWithSHA1AndDESCBC = "1.2.840.113549.1.5.10";
- public const string pbeWithSHA1AndRC2CBC = "1.2.840.113549.1.5.11";
-
- public PKCS5 () {}
- }
-
- public class PKCS9 {
-
- public const string friendlyName = "1.2.840.113549.1.9.20";
- public const string localKeyId = "1.2.840.113549.1.9.21";
-
- public PKCS9 () {}
- }
-
-
- internal class SafeBag {
- private string _bagOID;
- private ASN1 _asn1;
-
- public SafeBag(string bagOID, ASN1 asn1) {
- _bagOID = bagOID;
- _asn1 = asn1;
- }
-
- public string BagOID {
- get { return _bagOID; }
- }
-
- public ASN1 ASN1 {
- get { return _asn1; }
- }
- }
-
-
- public class PKCS12 : ICloneable {
-
- public const string pbeWithSHAAnd128BitRC4 = "1.2.840.113549.1.12.1.1";
- public const string pbeWithSHAAnd40BitRC4 = "1.2.840.113549.1.12.1.2";
- public const string pbeWithSHAAnd3KeyTripleDESCBC = "1.2.840.113549.1.12.1.3";
- public const string pbeWithSHAAnd2KeyTripleDESCBC = "1.2.840.113549.1.12.1.4";
- public const string pbeWithSHAAnd128BitRC2CBC = "1.2.840.113549.1.12.1.5";
- public const string pbeWithSHAAnd40BitRC2CBC = "1.2.840.113549.1.12.1.6";
-
- // bags
- public const string keyBag = "1.2.840.113549.1.12.10.1.1";
- public const string pkcs8ShroudedKeyBag = "1.2.840.113549.1.12.10.1.2";
- public const string certBag = "1.2.840.113549.1.12.10.1.3";
- public const string crlBag = "1.2.840.113549.1.12.10.1.4";
- public const string secretBag = "1.2.840.113549.1.12.10.1.5";
- public const string safeContentsBag = "1.2.840.113549.1.12.10.1.6";
-
- // types
- public const string x509Certificate = "1.2.840.113549.1.9.22.1";
- public const string sdsiCertificate = "1.2.840.113549.1.9.22.2";
- public const string x509Crl = "1.2.840.113549.1.9.23.1";
-
- // Adapted from BouncyCastle PKCS12ParametersGenerator.java
- public class DeriveBytes {
-
- public enum Purpose {
- Key,
- IV,
- MAC
- }
-
- static private byte[] keyDiversifier = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 };
- static private byte[] ivDiversifier = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 };
- static private byte[] macDiversifier = { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 };
-
- private string _hashName;
- private int _iterations;
- private byte[] _password;
- private byte[] _salt;
-
- public DeriveBytes () {}
-
- public string HashName {
- get { return _hashName; }
- set { _hashName = value; }
- }
-
- public int IterationCount {
- get { return _iterations; }
- set { _iterations = value; }
- }
-
- public byte[] Password {
- get { return (byte[]) _password.Clone (); }
- set {
- if (value == null)
- _password = new byte [0];
- else
- _password = (byte[]) value.Clone ();
- }
- }
-
- public byte[] Salt {
- get { return (byte[]) _salt.Clone (); }
- set {
- if (value != null)
- _salt = (byte[]) value.Clone ();
- else
- _salt = null;
- }
- }
-
- private void Adjust (byte[] a, int aOff, byte[] b)
- {
- int x = (b[b.Length - 1] & 0xff) + (a [aOff + b.Length - 1] & 0xff) + 1;
-
- a [aOff + b.Length - 1] = (byte) x;
- x >>= 8;
-
- for (int i = b.Length - 2; i >= 0; i--) {
- x += (b [i] & 0xff) + (a [aOff + i] & 0xff);
- a [aOff + i] = (byte) x;
- x >>= 8;
- }
- }
-
- private byte[] Derive (byte[] diversifier, int n)
- {
- HashAlgorithm digest = PKCS1.CreateFromName (_hashName);
- int u = (digest.HashSize >> 3); // div 8
- int v = 64;
- byte[] dKey = new byte [n];
-
- byte[] S;
- if ((_salt != null) && (_salt.Length != 0)) {
- S = new byte[v * ((_salt.Length + v - 1) / v)];
-
- for (int i = 0; i != S.Length; i++) {
- S[i] = _salt[i % _salt.Length];
- }
- }
- else {
- S = new byte[0];
- }
-
- byte[] P;
- if ((_password != null) && (_password.Length != 0)) {
- P = new byte[v * ((_password.Length + v - 1) / v)];
-
- for (int i = 0; i != P.Length; i++) {
- P[i] = _password[i % _password.Length];
- }
- }
- else {
- P = new byte[0];
- }
-
- byte[] I = new byte [S.Length + P.Length];
-
- Buffer.BlockCopy (S, 0, I, 0, S.Length);
- Buffer.BlockCopy (P, 0, I, S.Length, P.Length);
-
- byte[] B = new byte[v];
- int c = (n + u - 1) / u;
-
- for (int i = 1; i <= c; i++) {
- digest.TransformBlock (diversifier, 0, diversifier.Length, diversifier, 0);
- digest.TransformFinalBlock (I, 0, I.Length);
- byte[] A = digest.Hash;
- digest.Initialize ();
- for (int j = 1; j != _iterations; j++) {
- A = digest.ComputeHash (A, 0, A.Length);
- }
-
- for (int j = 0; j != B.Length; j++) {
- B [j] = A [j % A.Length];
- }
-
- for (int j = 0; j != I.Length / v; j++) {
- Adjust (I, j * v, B);
- }
-
- if (i == c) {
- Buffer.BlockCopy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u));
- }
- else {
- Buffer.BlockCopy(A, 0, dKey, (i - 1) * u, A.Length);
- }
- }
-
- return dKey;
- }
-
- public byte[] DeriveKey (int size)
- {
- return Derive (keyDiversifier, size);
- }
-
- public byte[] DeriveIV (int size)
- {
- return Derive (ivDiversifier, size);
- }
-
- public byte[] DeriveMAC (int size)
- {
- return Derive (macDiversifier, size);
- }
- }
-
- const int recommendedIterationCount = 2000;
-
- //private int _version;
- private byte[] _password;
- private ArrayList _keyBags;
- private ArrayList _secretBags;
- private X509CertificateCollection _certs;
- private bool _keyBagsChanged;
- private bool _secretBagsChanged;
- private bool _certsChanged;
- private int _iterations;
- private ArrayList _safeBags;
- private RandomNumberGenerator _rng;
-
- // constructors
-
- public PKCS12 ()
- {
- _iterations = recommendedIterationCount;
- _keyBags = new ArrayList ();
- _secretBags = new ArrayList ();
- _certs = new X509CertificateCollection ();
- _keyBagsChanged = false;
- _secretBagsChanged = false;
- _certsChanged = false;
- _safeBags = new ArrayList ();
- }
-
- public PKCS12 (byte[] data)
- : this ()
- {
- Password = null;
- Decode (data);
- }
-
- /*
- * PFX ::= SEQUENCE {
- * version INTEGER {v3(3)}(v3,...),
- * authSafe ContentInfo,
- * macData MacData OPTIONAL
- * }
- *
- * MacData ::= SEQUENCE {
- * mac DigestInfo,
- * macSalt OCTET STRING,
- * iterations INTEGER DEFAULT 1
- * -- Note: The default is for historical reasons and its use is deprecated. A higher
- * -- value, like 1024 is recommended.
- * }
- *
- * SafeContents ::= SEQUENCE OF SafeBag
- *
- * SafeBag ::= SEQUENCE {
- * bagId BAG-TYPE.&id ({PKCS12BagSet}),
- * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
- * bagAttributes SET OF PKCS12Attribute OPTIONAL
- * }
- */
- public PKCS12 (byte[] data, string password)
- : this ()
- {
- Password = password;
- Decode (data);
- }
-
- public PKCS12 (byte[] data, byte[] password)
- : this ()
- {
- _password = password;
- Decode (data);
- }
-
- private void Decode (byte[] data)
- {
- ASN1 pfx = new ASN1 (data);
- if (pfx.Tag != 0x30)
- throw new ArgumentException ("invalid data");
-
- ASN1 version = pfx [0];
- if (version.Tag != 0x02)
- throw new ArgumentException ("invalid PFX version");
- //_version = version.Value [0];
-
- PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (pfx [1]);
- if (authSafe.ContentType != PKCS7.Oid.data)
- throw new ArgumentException ("invalid authenticated safe");
-
- // now that we know it's a PKCS#12 file, check the (optional) MAC
- // before decoding anything else in the file
- if (pfx.Count > 2) {
- ASN1 macData = pfx [2];
- if (macData.Tag != 0x30)
- throw new ArgumentException ("invalid MAC");
-
- ASN1 mac = macData [0];
- if (mac.Tag != 0x30)
- throw new ArgumentException ("invalid MAC");
- ASN1 macAlgorithm = mac [0];
- string macOid = ASN1Convert.ToOid (macAlgorithm [0]);
- if (macOid != "1.3.14.3.2.26")
- throw new ArgumentException ("unsupported HMAC");
- byte[] macValue = mac [1].Value;
-
- ASN1 macSalt = macData [1];
- if (macSalt.Tag != 0x04)
- throw new ArgumentException ("missing MAC salt");
-
- _iterations = 1; // default value
- if (macData.Count > 2) {
- ASN1 iters = macData [2];
- if (iters.Tag != 0x02)
- throw new ArgumentException ("invalid MAC iteration");
- _iterations = ASN1Convert.ToInt32 (iters);
- }
-
- byte[] authSafeData = authSafe.Content [0].Value;
- byte[] calculatedMac = MAC (_password, macSalt.Value, _iterations, authSafeData);
- if (!Compare (macValue, calculatedMac)) {
- byte[] nullPassword = {0, 0};
- calculatedMac = MAC(nullPassword, macSalt.Value, _iterations, authSafeData);
- if (!Compare (macValue, calculatedMac))
- throw new CryptographicException ("Invalid MAC - file may have been tampe red!");
- _password = nullPassword;
- }
- }
-
- // we now returns to our original presentation - PFX
- ASN1 authenticatedSafe = new ASN1 (authSafe.Content [0].Value);
- for (int i=0; i < authenticatedSafe.Count; i++) {
- PKCS7.ContentInfo ci = new PKCS7.ContentInfo (authenticatedSafe [i]);
- switch (ci.ContentType) {
- case PKCS7.Oid.data:
- // unencrypted (by PKCS#12)
- ASN1 safeContents = new ASN1 (ci.Content [0].Value);
- for (int j=0; j < safeContents.Count; j++) {
- ASN1 safeBag = safeContents [j];
- ReadSafeBag (safeBag);
- }
- break;
- case PKCS7.Oid.encryptedData:
- // password encrypted
- PKCS7.EncryptedData ed = new PKCS7.EncryptedData (ci.Content [0]);
- ASN1 decrypted = new ASN1 (Decrypt (ed));
- for (int j=0; j < decrypted.Count; j++) {
- ASN1 safeBag = decrypted [j];
- ReadSafeBag (safeBag);
- }
- break;
- case PKCS7.Oid.envelopedData:
- // public key encrypted
- throw new NotImplementedException ("public key encrypted");
- default:
- throw new ArgumentException ("unknown authenticatedSafe");
- }
- }
- }
-
- ~PKCS12 ()
- {
- if (_password != null) {
- Array.Clear (_password, 0, _password.Length);
- }
- _password = null;
- }
-
- // properties
-
- public string Password {
- set {
- // Clear old password.
- if (_password != null)
- Array.Clear (_password, 0, _password.Length);
- _password = null;
- if (value != null) {
- if (value.Length > 0) {
- int size = value.Length;
- int nul = 0;
- if (size < MaximumPasswordLength) {
- // if not present, add space for a NULL (0x00) character
- if (value[size - 1] != 0x00)
- nul = 1;
- } else {
- size = MaximumPasswordLength;
- }
- _password = new byte[(size + nul) << 1]; // double for unicode
- Encoding.BigEndianUnicode.GetBytes (value, 0, size, _password, 0);
- } else {
- // double-byte (Unicode) NULL (0x00) - see bug #79617
- _password = new byte[2];
- }
- }
- }
- }
-
- public int IterationCount {
- get { return _iterations; }
- set { _iterations = value; }
- }
-
- public ArrayList Keys {
- get {
- if (_keyBagsChanged) {
- _keyBags.Clear ();
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (keyBag)) {
- ASN1 safeBag = sb.ASN1;
- ASN1 bagValue = safeBag [1];
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
- byte[] privateKey = pki.PrivateKey;
- switch (privateKey [0]) {
- case 0x02:
- DSAParameters p = new DSAParameters (); // FIXME
- _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
- break;
- case 0x30:
- _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
- break;
- default:
- break;
- }
- Array.Clear (privateKey, 0, privateKey.Length);
-
- } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
- ASN1 safeBag = sb.ASN1;
- ASN1 bagValue = safeBag [1];
- PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
- byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
- byte[] privateKey = pki.PrivateKey;
- switch (privateKey [0]) {
- case 0x02:
- DSAParameters p = new DSAParameters (); // FIXME
- _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
- break;
- case 0x30:
- _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
- break;
- default:
- break;
- }
- Array.Clear (privateKey, 0, privateKey.Length);
- Array.Clear (decrypted, 0, decrypted.Length);
- }
- }
- _keyBagsChanged = false;
- }
- return ArrayList.ReadOnly(_keyBags);
- }
- }
-
- public ArrayList Secrets {
- get {
- if (_secretBagsChanged) {
- _secretBags.Clear ();
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (secretBag)) {
- ASN1 safeBag = sb.ASN1;
- ASN1 bagValue = safeBag [1];
- byte[] secret = bagValue.Value;
- _secretBags.Add(secret);
- }
- }
- _secretBagsChanged = false;
- }
- return ArrayList.ReadOnly(_secretBags);
- }
- }
-
- public X509CertificateCollection Certificates {
- get {
- if (_certsChanged) {
- _certs.Clear ();
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (certBag)) {
- ASN1 safeBag = sb.ASN1;
- ASN1 bagValue = safeBag [1];
- PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
- _certs.Add (new X509Certificate (cert.Content [0].Value));
- }
- }
- _certsChanged = false;
- }
- return _certs;
- }
- }
-
- internal RandomNumberGenerator RNG {
- get {
- if (_rng == null)
- _rng = RandomNumberGenerator.Create ();
- return _rng;
- }
- }
-
- // private methods
-
- private bool Compare (byte[] expected, byte[] actual)
- {
- bool compare = false;
- if (expected.Length == actual.Length) {
- for (int i=0; i < expected.Length; i++) {
- if (expected [i] != actual [i])
- return false;
- }
- compare = true;
- }
- return compare;
- }
-
- private SymmetricAlgorithm GetSymmetricAlgorithm (string algorithmOid, byte[] salt, int iterationCount)
- {
- string algorithm = null;
- int keyLength = 8; // 64 bits (default)
- int ivLength = 8; // 64 bits (default)
-
- PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes ();
- pd.Password = _password;
- pd.Salt = salt;
- pd.IterationCount = iterationCount;
-
- switch (algorithmOid) {
- case PKCS5.pbeWithMD2AndDESCBC: // no unit test available
- pd.HashName = "MD2";
- algorithm = "DES";
- break;
- case PKCS5.pbeWithMD5AndDESCBC: // no unit test available
- pd.HashName = "MD5";
- algorithm = "DES";
- break;
- case PKCS5.pbeWithMD2AndRC2CBC: // no unit test available
- // TODO - RC2-CBC-Parameter (PKCS5)
- // if missing default to 32 bits !!!
- pd.HashName = "MD2";
- algorithm = "RC2";
- keyLength = 4; // default
- break;
- case PKCS5.pbeWithMD5AndRC2CBC: // no unit test available
- // TODO - RC2-CBC-Parameter (PKCS5)
- // if missing default to 32 bits !!!
- pd.HashName = "MD5";
- algorithm = "RC2";
- keyLength = 4; // default
- break;
- case PKCS5.pbeWithSHA1AndDESCBC: // no unit test available
- pd.HashName = "SHA1";
- algorithm = "DES";
- break;
- case PKCS5.pbeWithSHA1AndRC2CBC: // no unit test available
- // TODO - RC2-CBC-Parameter (PKCS5)
- // if missing default to 32 bits !!!
- pd.HashName = "SHA1";
- algorithm = "RC2";
- keyLength = 4; // default
- break;
- case PKCS12.pbeWithSHAAnd128BitRC4: // no unit test available
- pd.HashName = "SHA1";
- algorithm = "RC4";
- keyLength = 16;
- ivLength = 0; // N/A
- break;
- case PKCS12.pbeWithSHAAnd40BitRC4: // no unit test available
- pd.HashName = "SHA1";
- algorithm = "RC4";
- keyLength = 5;
- ivLength = 0; // N/A
- break;
- case PKCS12.pbeWithSHAAnd3KeyTripleDESCBC:
- pd.HashName = "SHA1";
- algorithm = "TripleDES";
- keyLength = 24;
- break;
- case PKCS12.pbeWithSHAAnd2KeyTripleDESCBC: // no unit test available
- pd.HashName = "SHA1";
- algorithm = "TripleDES";
- keyLength = 16;
- break;
- case PKCS12.pbeWithSHAAnd128BitRC2CBC: // no unit test available
- pd.HashName = "SHA1";
- algorithm = "RC2";
- keyLength = 16;
- break;
- case PKCS12.pbeWithSHAAnd40BitRC2CBC:
- pd.HashName = "SHA1";
- algorithm = "RC2";
- keyLength = 5;
- break;
- default:
- throw new NotSupportedException ("unknown oid " + algorithm);
- }
-
- SymmetricAlgorithm sa = null;
- sa = SymmetricAlgorithm.Create(algorithm);
- sa.Key = pd.DeriveKey (keyLength);
- // IV required only for block ciphers (not stream ciphers)
- if (ivLength > 0) {
- sa.IV = pd.DeriveIV (ivLength);
- sa.Mode = CipherMode.CBC;
- }
- return sa;
- }
-
- public byte[] Decrypt (string algorithmOid, byte[] salt, int iterationCount, byte[] encryptedData)
- {
- SymmetricAlgorithm sa = null;
- byte[] result = null;
- try {
- sa = GetSymmetricAlgorithm (algorithmOid, salt, iterationCount);
- ICryptoTransform ct = sa.CreateDecryptor ();
- result = ct.TransformFinalBlock (encryptedData, 0, encryptedData.Length);
- }
- finally {
- if (sa != null)
- sa.Clear ();
- }
- return result;
- }
-
- public byte[] Decrypt (PKCS7.EncryptedData ed)
- {
- return Decrypt (ed.EncryptionAlgorithm.ContentType,
- ed.EncryptionAlgorithm.Content [0].Value,
- ASN1Convert.ToInt32 (ed.EncryptionAlgorithm.Content [1]),
- ed.EncryptedContent);
- }
-
- public byte[] Encrypt (string algorithmOid, byte[] salt, int iterationCount, byte[] data)
- {
- byte[] result = null;
- using (SymmetricAlgorithm sa = GetSymmetricAlgorithm (algorithmOid, salt, iterationCount)) {
- ICryptoTransform ct = sa.CreateEncryptor ();
- result = ct.TransformFinalBlock (data, 0, data.Length);
- }
- return result;
- }
-
- private DSAParameters GetExistingParameters (out bool found)
- {
- foreach (X509Certificate cert in Certificates) {
- // FIXME: that won't work if parts of the parameters are missing
- if (cert.KeyAlgorithmParameters != null) {
- DSA dsa = cert.DSA;
- if (dsa != null) {
- found = true;
- return dsa.ExportParameters (false);
- }
- }
- }
- found = false;
- return new DSAParameters ();
- }
-
- private void AddPrivateKey (PKCS8.PrivateKeyInfo pki)
- {
- byte[] privateKey = pki.PrivateKey;
- switch (privateKey [0]) {
- case 0x02:
- bool found;
- DSAParameters p = GetExistingParameters (out found);
- if (found) {
- _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
- }
- break;
- case 0x30:
- _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
- break;
- default:
- Array.Clear (privateKey, 0, privateKey.Length);
- throw new CryptographicException ("Unknown private key format");
- }
- Array.Clear (privateKey, 0, privateKey.Length);
- }
-
- private void ReadSafeBag (ASN1 safeBag)
- {
- if (safeBag.Tag != 0x30)
- throw new ArgumentException ("invalid safeBag");
-
- ASN1 bagId = safeBag [0];
- if (bagId.Tag != 0x06)
- throw new ArgumentException ("invalid safeBag id");
-
- ASN1 bagValue = safeBag [1];
- string oid = ASN1Convert.ToOid (bagId);
- switch (oid) {
- case keyBag:
- // NEED UNIT TEST
- AddPrivateKey (new PKCS8.PrivateKeyInfo (bagValue.Value));
- break;
- case pkcs8ShroudedKeyBag:
- PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
- byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
- AddPrivateKey (new PKCS8.PrivateKeyInfo (decrypted));
- Array.Clear (decrypted, 0, decrypted.Length);
- break;
- case certBag:
- PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
- if (cert.ContentType != x509Certificate)
- throw new NotSupportedException ("unsupport certificate type");
- X509Certificate x509 = new X509Certificate (cert.Content [0].Value);
- _certs.Add (x509);
- break;
- case crlBag:
- // TODO
- break;
- case secretBag:
- byte[] secret = bagValue.Value;
- _secretBags.Add(secret);
- break;
- case safeContentsBag:
- // TODO - ? recurse ?
- break;
- default:
- throw new ArgumentException ("unknown safeBag oid");
- }
-
- if (safeBag.Count > 2) {
- ASN1 bagAttributes = safeBag [2];
- if (bagAttributes.Tag != 0x31)
- throw new ArgumentException ("invalid safeBag attributes id");
-
- for (int i = 0; i < bagAttributes.Count; i++) {
- ASN1 pkcs12Attribute = bagAttributes[i];
-
- if (pkcs12Attribute.Tag != 0x30)
- throw new ArgumentException ("invalid PKCS12 attributes id");
-
- ASN1 attrId = pkcs12Attribute [0];
- if (attrId.Tag != 0x06)
- throw new ArgumentException ("invalid attribute id");
-
- string attrOid = ASN1Convert.ToOid (attrId);
-
- ASN1 attrValues = pkcs12Attribute[1];
- for (int j = 0; j < attrValues.Count; j++) {
- ASN1 attrValue = attrValues[j];
-
- switch (attrOid) {
- case PKCS9.friendlyName:
- if (attrValue.Tag != 0x1e)
- throw new ArgumentException ("invalid attribute value id");
- break;
- case PKCS9.localKeyId:
- if (attrValue.Tag != 0x04)
- throw new ArgumentException ("invalid attribute value id");
- break;
- default:
- // Unknown OID -- don't check Tag
- break;
- }
- }
- }
- }
-
- _safeBags.Add (new SafeBag(oid, safeBag));
- }
-
- private ASN1 Pkcs8ShroudedKeyBagSafeBag (AsymmetricAlgorithm aa, IDictionary attributes)
- {
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo ();
- if (aa is RSA) {
- pki.Algorithm = "1.2.840.113549.1.1.1";
- pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((RSA)aa);
- }
- else if (aa is DSA) {
- pki.Algorithm = null;
- pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((DSA)aa);
- }
- else
- throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ());
-
- PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo ();
- epki.Algorithm = pbeWithSHAAnd3KeyTripleDESCBC;
- epki.IterationCount = _iterations;
- epki.EncryptedData = Encrypt (pbeWithSHAAnd3KeyTripleDESCBC, epki.Salt, _iterations, pki.GetBytes ());
-
- ASN1 safeBag = new ASN1 (0x30);
- safeBag.Add (ASN1Convert.FromOid (pkcs8ShroudedKeyBag));
- ASN1 bagValue = new ASN1 (0xA0);
- bagValue.Add (new ASN1 (epki.GetBytes ()));
- safeBag.Add (bagValue);
-
- if (attributes != null) {
- ASN1 bagAttributes = new ASN1 (0x31);
- IDictionaryEnumerator de = attributes.GetEnumerator ();
-
- while (de.MoveNext ()) {
- string oid = (string)de.Key;
- switch (oid) {
- case PKCS9.friendlyName:
- ArrayList names = (ArrayList)de.Value;
- if (names.Count > 0) {
- ASN1 pkcs12Attribute = new ASN1 (0x30);
- pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
- ASN1 attrValues = new ASN1 (0x31);
- foreach (byte[] name in names) {
- ASN1 attrValue = new ASN1 (0x1e);
- attrValue.Value = name;
- attrValues.Add (attrValue);
- }
- pkcs12Attribute.Add (attrValues);
- bagAttributes.Add (pkcs12Attribute);
- }
- break;
- case PKCS9.localKeyId:
- ArrayList keys = (ArrayList)de.Value;
- if (keys.Count > 0) {
- ASN1 pkcs12Attribute = new ASN1 (0x30);
- pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
- ASN1 attrValues = new ASN1 (0x31);
- foreach (byte[] key in keys) {
- ASN1 attrValue = new ASN1 (0x04);
- attrValue.Value = key;
- attrValues.Add (attrValue);
- }
- pkcs12Attribute.Add (attrValues);
- bagAttributes.Add (pkcs12Attribute);
- }
- break;
- default:
- break;
- }
- }
-
- if (bagAttributes.Count > 0) {
- safeBag.Add (bagAttributes);
- }
- }
-
- return safeBag;
- }
-
- private ASN1 KeyBagSafeBag (AsymmetricAlgorithm aa, IDictionary attributes)
- {
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo ();
- if (aa is RSA) {
- pki.Algorithm = "1.2.840.113549.1.1.1";
- pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((RSA)aa);
- }
- else if (aa is DSA) {
- pki.Algorithm = null;
- pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((DSA)aa);
- }
- else
- throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ());
-
- ASN1 safeBag = new ASN1 (0x30);
- safeBag.Add (ASN1Convert.FromOid (keyBag));
- ASN1 bagValue = new ASN1 (0xA0);
- bagValue.Add (new ASN1 (pki.GetBytes ()));
- safeBag.Add (bagValue);
-
- if (attributes != null) {
- ASN1 bagAttributes = new ASN1 (0x31);
- IDictionaryEnumerator de = attributes.GetEnumerator ();
-
- while (de.MoveNext ()) {
- string oid = (string)de.Key;
- switch (oid) {
- case PKCS9.friendlyName:
- ArrayList names = (ArrayList)de.Value;
- if (names.Count > 0) {
- ASN1 pkcs12Attribute = new ASN1 (0x30);
- pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
- ASN1 attrValues = new ASN1 (0x31);
- foreach (byte[] name in names) {
- ASN1 attrValue = new ASN1 (0x1e);
- attrValue.Value = name;
- attrValues.Add (attrValue);
- }
- pkcs12Attribute.Add (attrValues);
- bagAttributes.Add (pkcs12Attribute);
- }
- break;
- case PKCS9.localKeyId:
- ArrayList keys = (ArrayList)de.Value;
- if (keys.Count > 0) {
- ASN1 pkcs12Attribute = new ASN1 (0x30);
- pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
- ASN1 attrValues = new ASN1 (0x31);
- foreach (byte[] key in keys) {
- ASN1 attrValue = new ASN1 (0x04);
- attrValue.Value = key;
- attrValues.Add (attrValue);
- }
- pkcs12Attribute.Add (attrValues);
- bagAttributes.Add (pkcs12Attribute);
- }
- break;
- default:
- break;
- }
- }
-
- if (bagAttributes.Count > 0) {
- safeBag.Add (bagAttributes);
- }
- }
-
- return safeBag;
- }
-
- private ASN1 SecretBagSafeBag (byte[] secret, IDictionary attributes)
- {
- ASN1 safeBag = new ASN1 (0x30);
- safeBag.Add (ASN1Convert.FromOid (secretBag));
- ASN1 bagValue = new ASN1 (0x80, secret);
- safeBag.Add (bagValue);
-
- if (attributes != null) {
- ASN1 bagAttributes = new ASN1 (0x31);
- IDictionaryEnumerator de = attributes.GetEnumerator ();
-
- while (de.MoveNext ()) {
- string oid = (string)de.Key;
- switch (oid) {
- case PKCS9.friendlyName:
- ArrayList names = (ArrayList)de.Value;
- if (names.Count > 0) {
- ASN1 pkcs12Attribute = new ASN1 (0x30);
- pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
- ASN1 attrValues = new ASN1 (0x31);
- foreach (byte[] name in names) {
- ASN1 attrValue = new ASN1 (0x1e);
- attrValue.Value = name;
- attrValues.Add (attrValue);
- }
- pkcs12Attribute.Add (attrValues);
- bagAttributes.Add (pkcs12Attribute);
- }
- break;
- case PKCS9.localKeyId:
- ArrayList keys = (ArrayList)de.Value;
- if (keys.Count > 0) {
- ASN1 pkcs12Attribute = new ASN1 (0x30);
- pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
- ASN1 attrValues = new ASN1 (0x31);
- foreach (byte[] key in keys) {
- ASN1 attrValue = new ASN1 (0x04);
- attrValue.Value = key;
- attrValues.Add (attrValue);
- }
- pkcs12Attribute.Add (attrValues);
- bagAttributes.Add (pkcs12Attribute);
- }
- break;
- default:
- break;
- }
- }
-
- if (bagAttributes.Count > 0) {
- safeBag.Add (bagAttributes);
- }
- }
-
- return safeBag;
- }
-
- private ASN1 CertificateSafeBag (X509Certificate x509, IDictionary attributes)
- {
- ASN1 encapsulatedCertificate = new ASN1 (0x04, x509.RawData);
-
- PKCS7.ContentInfo ci = new PKCS7.ContentInfo ();
- ci.ContentType = x509Certificate;
- ci.Content.Add (encapsulatedCertificate);
-
- ASN1 bagValue = new ASN1 (0xA0);
- bagValue.Add (ci.ASN1);
-
- ASN1 safeBag = new ASN1 (0x30);
- safeBag.Add (ASN1Convert.FromOid (certBag));
- safeBag.Add (bagValue);
-
- if (attributes != null) {
- ASN1 bagAttributes = new ASN1 (0x31);
- IDictionaryEnumerator de = attributes.GetEnumerator ();
-
- while (de.MoveNext ()) {
- string oid = (string)de.Key;
- switch (oid) {
- case PKCS9.friendlyName:
- ArrayList names = (ArrayList)de.Value;
- if (names.Count > 0) {
- ASN1 pkcs12Attribute = new ASN1 (0x30);
- pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
- ASN1 attrValues = new ASN1 (0x31);
- foreach (byte[] name in names) {
- ASN1 attrValue = new ASN1 (0x1e);
- attrValue.Value = name;
- attrValues.Add (attrValue);
- }
- pkcs12Attribute.Add (attrValues);
- bagAttributes.Add (pkcs12Attribute);
- }
- break;
- case PKCS9.localKeyId:
- ArrayList keys = (ArrayList)de.Value;
- if (keys.Count > 0) {
- ASN1 pkcs12Attribute = new ASN1 (0x30);
- pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
- ASN1 attrValues = new ASN1 (0x31);
- foreach (byte[] key in keys) {
- ASN1 attrValue = new ASN1 (0x04);
- attrValue.Value = key;
- attrValues.Add (attrValue);
- }
- pkcs12Attribute.Add (attrValues);
- bagAttributes.Add (pkcs12Attribute);
- }
- break;
- default:
- break;
- }
- }
-
- if (bagAttributes.Count > 0) {
- safeBag.Add (bagAttributes);
- }
- }
-
- return safeBag;
- }
-
- private byte[] MAC (byte[] password, byte[] salt, int iterations, byte[] data)
- {
- PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes ();
- pd.HashName = "SHA1";
- pd.Password = password;
- pd.Salt = salt;
- pd.IterationCount = iterations;
-
- HMACSHA1 hmac = (HMACSHA1) HMACSHA1.Create ();
- hmac.Key = pd.DeriveMAC (20);
- return hmac.ComputeHash (data, 0, data.Length);
- }
-
- /*
- * SafeContents ::= SEQUENCE OF SafeBag
- *
- * SafeBag ::= SEQUENCE {
- * bagId BAG-TYPE.&id ({PKCS12BagSet}),
- * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
- * bagAttributes SET OF PKCS12Attribute OPTIONAL
- * }
- */
- public byte[] GetBytes ()
- {
- // TODO (incomplete)
- ASN1 safeBagSequence = new ASN1 (0x30);
-
- // Sync Safe Bag list since X509CertificateCollection may be updated
- ArrayList scs = new ArrayList ();
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (certBag)) {
- ASN1 safeBag = sb.ASN1;
- ASN1 bagValue = safeBag [1];
- PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
- scs.Add (new X509Certificate (cert.Content [0].Value));
- }
- }
-
- ArrayList addcerts = new ArrayList ();
- ArrayList removecerts = new ArrayList ();
-
- foreach (X509Certificate c in Certificates) {
- bool found = false;
-
- foreach (X509Certificate lc in scs) {
- if (Compare (c.RawData, lc.RawData)) {
- found = true;
- }
- }
-
- if (!found) {
- addcerts.Add (c);
- }
- }
- foreach (X509Certificate c in scs) {
- bool found = false;
-
- foreach (X509Certificate lc in Certificates) {
- if (Compare (c.RawData, lc.RawData)) {
- found = true;
- }
- }
-
- if (!found) {
- removecerts.Add (c);
- }
- }
-
- foreach (X509Certificate c in removecerts) {
- RemoveCertificate (c);
- }
-
- foreach (X509Certificate c in addcerts) {
- AddCertificate (c);
- }
- // Sync done
-
- if (_safeBags.Count > 0) {
- ASN1 certsSafeBag = new ASN1 (0x30);
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (certBag)) {
- certsSafeBag.Add (sb.ASN1);
- }
- }
-
- if (certsSafeBag.Count > 0) {
- PKCS7.ContentInfo contentInfo = EncryptedContentInfo (certsSafeBag, pbeWithSHAAnd3KeyTripleDESCBC);
- safeBagSequence.Add (contentInfo.ASN1);
- }
- }
-
- if (_safeBags.Count > 0) {
- ASN1 safeContents = new ASN1 (0x30);
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (keyBag) ||
- sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
- safeContents.Add (sb.ASN1);
- }
- }
- if (safeContents.Count > 0) {
- ASN1 content = new ASN1 (0xA0);
- content.Add (new ASN1 (0x04, safeContents.GetBytes ()));
-
- PKCS7.ContentInfo keyBag = new PKCS7.ContentInfo (PKCS7.Oid.data);
- keyBag.Content = content;
- safeBagSequence.Add (keyBag.ASN1);
- }
- }
-
- // Doing SecretBags separately in case we want to change their encryption independently.
- if (_safeBags.Count > 0) {
- ASN1 secretsSafeBag = new ASN1 (0x30);
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (secretBag)) {
- secretsSafeBag.Add (sb.ASN1);
- }
- }
-
- if (secretsSafeBag.Count > 0) {
- PKCS7.ContentInfo contentInfo = EncryptedContentInfo (secretsSafeBag, pbeWithSHAAnd3KeyTripleDESCBC);
- safeBagSequence.Add (contentInfo.ASN1);
- }
- }
-
-
- ASN1 encapsulates = new ASN1 (0x04, safeBagSequence.GetBytes ());
- ASN1 ci = new ASN1 (0xA0);
- ci.Add (encapsulates);
- PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (PKCS7.Oid.data);
- authSafe.Content = ci;
-
- ASN1 macData = new ASN1 (0x30);
- if (_password != null) {
- // only for password based encryption
- byte[] salt = new byte [20];
- RNG.GetBytes (salt);
- byte[] macValue = MAC (_password, salt, _iterations, authSafe.Content [0].Value);
- ASN1 oidSeq = new ASN1 (0x30);
- oidSeq.Add (ASN1Convert.FromOid ("1.3.14.3.2.26")); // SHA1
- oidSeq.Add (new ASN1 (0x05));
-
- ASN1 mac = new ASN1 (0x30);
- mac.Add (oidSeq);
- mac.Add (new ASN1 (0x04, macValue));
-
- macData.Add (mac);
- macData.Add (new ASN1 (0x04, salt));
- macData.Add (ASN1Convert.FromInt32 (_iterations));
- }
-
- ASN1 version = new ASN1 (0x02, new byte [1] { 0x03 });
-
- ASN1 pfx = new ASN1 (0x30);
- pfx.Add (version);
- pfx.Add (authSafe.ASN1);
- if (macData.Count > 0) {
- // only for password based encryption
- pfx.Add (macData);
- }
-
- return pfx.GetBytes ();
- }
-
- // Creates an encrypted PKCS#7 ContentInfo with safeBags as its SafeContents. Used in GetBytes(), above.
- private PKCS7.ContentInfo EncryptedContentInfo(ASN1 safeBags, string algorithmOid)
- {
- byte[] salt = new byte [8];
- RNG.GetBytes (salt);
-
- ASN1 seqParams = new ASN1 (0x30);
- seqParams.Add (new ASN1 (0x04, salt));
- seqParams.Add (ASN1Convert.FromInt32 (_iterations));
-
- ASN1 seqPbe = new ASN1 (0x30);
- seqPbe.Add (ASN1Convert.FromOid (algorithmOid));
- seqPbe.Add (seqParams);
-
- byte[] encrypted = Encrypt (algorithmOid, salt, _iterations, safeBags.GetBytes ());
- ASN1 encryptedContent = new ASN1 (0x80, encrypted);
-
- ASN1 seq = new ASN1 (0x30);
- seq.Add (ASN1Convert.FromOid (PKCS7.Oid.data));
- seq.Add (seqPbe);
- seq.Add (encryptedContent);
-
- ASN1 version = new ASN1 (0x02, new byte [1] { 0x00 });
- ASN1 encData = new ASN1 (0x30);
- encData.Add (version);
- encData.Add (seq);
-
- ASN1 finalContent = new ASN1 (0xA0);
- finalContent.Add (encData);
-
- PKCS7.ContentInfo bag = new PKCS7.ContentInfo (PKCS7.Oid.encryptedData);
- bag.Content = finalContent;
- return bag;
- }
-
- public void AddCertificate (X509Certificate cert)
- {
- AddCertificate (cert, null);
- }
-
- public void AddCertificate (X509Certificate cert, IDictionary attributes)
- {
- bool found = false;
-
- for (int i = 0; !found && i < _safeBags.Count; i++) {
- SafeBag sb = (SafeBag)_safeBags [i];
-
- if (sb.BagOID.Equals (certBag)) {
- ASN1 safeBag = sb.ASN1;
- ASN1 bagValue = safeBag [1];
- PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
- X509Certificate c = new X509Certificate (crt.Content [0].Value);
- if (Compare (cert.RawData, c.RawData)) {
- found = true;
- }
- }
- }
-
- if (!found) {
- _safeBags.Add (new SafeBag (certBag, CertificateSafeBag (cert, attributes)));
- _certsChanged = true;
- }
- }
-
- public void RemoveCertificate (X509Certificate cert)
- {
- RemoveCertificate (cert, null);
- }
-
- public void RemoveCertificate (X509Certificate cert, IDictionary attrs)
- {
- int certIndex = -1;
-
- for (int i = 0; certIndex == -1 && i < _safeBags.Count; i++) {
- SafeBag sb = (SafeBag)_safeBags [i];
-
- if (sb.BagOID.Equals (certBag)) {
- ASN1 safeBag = sb.ASN1;
- ASN1 bagValue = safeBag [1];
- PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
- X509Certificate c = new X509Certificate (crt.Content [0].Value);
- if (Compare (cert.RawData, c.RawData)) {
- if (attrs != null) {
- if (safeBag.Count == 3) {
- ASN1 bagAttributes = safeBag [2];
- int bagAttributesFound = 0;
- for (int j = 0; j < bagAttributes.Count; j++) {
- ASN1 pkcs12Attribute = bagAttributes [j];
- ASN1 attrId = pkcs12Attribute [0];
- string ao = ASN1Convert.ToOid (attrId);
- ArrayList dattrValues = (ArrayList)attrs [ao];
-
- if (dattrValues != null) {
- ASN1 attrValues = pkcs12Attribute [1];
-
- if (dattrValues.Count == attrValues.Count) {
- int attrValuesFound = 0;
- for (int k = 0; k < attrValues.Count; k++) {
- ASN1 attrValue = attrValues [k];
- byte[] value = (byte[])dattrValues [k];
-
- if (Compare (value, attrValue.Value)) {
- attrValuesFound += 1;
- }
- }
- if (attrValuesFound == attrValues.Count) {
- bagAttributesFound += 1;
- }
- }
- }
- }
- if (bagAttributesFound == bagAttributes.Count) {
- certIndex = i;
- }
- }
- } else {
- certIndex = i;
- }
- }
- }
- }
-
- if (certIndex != -1) {
- _safeBags.RemoveAt (certIndex);
- _certsChanged = true;
- }
- }
-
- private bool CompareAsymmetricAlgorithm (AsymmetricAlgorithm a1, AsymmetricAlgorithm a2)
- {
- // fast path
- if (a1.KeySize != a2.KeySize)
- return false;
- // compare public keys - if they match we can assume the private match too
- return (a1.ToXmlString (false) == a2.ToXmlString (false));
- }
-
- public void AddPkcs8ShroudedKeyBag (AsymmetricAlgorithm aa)
- {
- AddPkcs8ShroudedKeyBag (aa, null);
- }
-
- public void AddPkcs8ShroudedKeyBag (AsymmetricAlgorithm aa, IDictionary attributes)
- {
- bool found = false;
-
- for (int i = 0; !found && i < _safeBags.Count; i++) {
- SafeBag sb = (SafeBag)_safeBags [i];
-
- if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
- ASN1 bagValue = sb.ASN1 [1];
- PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
- byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
- byte[] privateKey = pki.PrivateKey;
-
- AsymmetricAlgorithm saa = null;
- switch (privateKey [0]) {
- case 0x02:
- DSAParameters p = new DSAParameters (); // FIXME
- saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
- break;
- case 0x30:
- saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
- break;
- default:
- Array.Clear (decrypted, 0, decrypted.Length);
- Array.Clear (privateKey, 0, privateKey.Length);
- throw new CryptographicException ("Unknown private key format");
- }
-
- Array.Clear (decrypted, 0, decrypted.Length);
- Array.Clear (privateKey, 0, privateKey.Length);
-
- if (CompareAsymmetricAlgorithm (aa , saa)) {
- found = true;
- }
- }
- }
-
- if (!found) {
- _safeBags.Add (new SafeBag (pkcs8ShroudedKeyBag, Pkcs8ShroudedKeyBagSafeBag (aa, attributes)));
- _keyBagsChanged = true;
- }
- }
-
- public void RemovePkcs8ShroudedKeyBag (AsymmetricAlgorithm aa)
- {
- int aaIndex = -1;
-
- for (int i = 0; aaIndex == -1 && i < _safeBags.Count; i++) {
- SafeBag sb = (SafeBag)_safeBags [i];
-
- if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
- ASN1 bagValue = sb.ASN1 [1];
- PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
- byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
- byte[] privateKey = pki.PrivateKey;
-
- AsymmetricAlgorithm saa = null;
- switch (privateKey [0]) {
- case 0x02:
- DSAParameters p = new DSAParameters (); // FIXME
- saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
- break;
- case 0x30:
- saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
- break;
- default:
- Array.Clear (decrypted, 0, decrypted.Length);
- Array.Clear (privateKey, 0, privateKey.Length);
- throw new CryptographicException ("Unknown private key format");
- }
-
- Array.Clear (decrypted, 0, decrypted.Length);
- Array.Clear (privateKey, 0, privateKey.Length);
-
- if (CompareAsymmetricAlgorithm (aa, saa)) {
- aaIndex = i;
- }
- }
- }
-
- if (aaIndex != -1) {
- _safeBags.RemoveAt (aaIndex);
- _keyBagsChanged = true;
- }
- }
-
- public void AddKeyBag (AsymmetricAlgorithm aa)
- {
- AddKeyBag (aa, null);
- }
-
- public void AddKeyBag (AsymmetricAlgorithm aa, IDictionary attributes)
- {
- bool found = false;
-
- for (int i = 0; !found && i < _safeBags.Count; i++) {
- SafeBag sb = (SafeBag)_safeBags [i];
-
- if (sb.BagOID.Equals (keyBag)) {
- ASN1 bagValue = sb.ASN1 [1];
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
- byte[] privateKey = pki.PrivateKey;
-
- AsymmetricAlgorithm saa = null;
- switch (privateKey [0]) {
- case 0x02:
- DSAParameters p = new DSAParameters (); // FIXME
- saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
- break;
- case 0x30:
- saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
- break;
- default:
- Array.Clear (privateKey, 0, privateKey.Length);
- throw new CryptographicException ("Unknown private key format");
- }
-
- Array.Clear (privateKey, 0, privateKey.Length);
-
- if (CompareAsymmetricAlgorithm (aa, saa)) {
- found = true;
- }
- }
- }
-
- if (!found) {
- _safeBags.Add (new SafeBag (keyBag, KeyBagSafeBag (aa, attributes)));
- _keyBagsChanged = true;
- }
- }
-
- public void RemoveKeyBag (AsymmetricAlgorithm aa)
- {
- int aaIndex = -1;
-
- for (int i = 0; aaIndex == -1 && i < _safeBags.Count; i++) {
- SafeBag sb = (SafeBag)_safeBags [i];
-
- if (sb.BagOID.Equals (keyBag)) {
- ASN1 bagValue = sb.ASN1 [1];
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
- byte[] privateKey = pki.PrivateKey;
-
- AsymmetricAlgorithm saa = null;
- switch (privateKey [0]) {
- case 0x02:
- DSAParameters p = new DSAParameters (); // FIXME
- saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
- break;
- case 0x30:
- saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
- break;
- default:
- Array.Clear (privateKey, 0, privateKey.Length);
- throw new CryptographicException ("Unknown private key format");
- }
-
- Array.Clear (privateKey, 0, privateKey.Length);
-
- if (CompareAsymmetricAlgorithm (aa, saa)) {
- aaIndex = i;
- }
- }
- }
-
- if (aaIndex != -1) {
- _safeBags.RemoveAt (aaIndex);
- _keyBagsChanged = true;
- }
- }
-
- public void AddSecretBag (byte[] secret)
- {
- AddSecretBag (secret, null);
- }
-
- public void AddSecretBag (byte[] secret, IDictionary attributes)
- {
- bool found = false;
-
- for (int i = 0; !found && i < _safeBags.Count; i++) {
- SafeBag sb = (SafeBag)_safeBags [i];
-
- if (sb.BagOID.Equals (secretBag)) {
- ASN1 bagValue = sb.ASN1 [1];
- byte[] ssecret = bagValue.Value;
-
- if (Compare (secret, ssecret)) {
- found = true;
- }
- }
- }
-
- if (!found) {
- _safeBags.Add (new SafeBag (secretBag, SecretBagSafeBag (secret, attributes)));
- _secretBagsChanged = true;
- }
- }
-
- public void RemoveSecretBag (byte[] secret)
- {
- int sIndex = -1;
-
- for (int i = 0; sIndex == -1 && i < _safeBags.Count; i++) {
- SafeBag sb = (SafeBag)_safeBags [i];
-
- if (sb.BagOID.Equals (secretBag)) {
- ASN1 bagValue = sb.ASN1 [1];
- byte[] ssecret = bagValue.Value;
-
- if (Compare (secret, ssecret)) {
- sIndex = i;
- }
- }
- }
-
- if (sIndex != -1) {
- _safeBags.RemoveAt (sIndex);
- _secretBagsChanged = true;
- }
- }
-
- public AsymmetricAlgorithm GetAsymmetricAlgorithm (IDictionary attrs)
- {
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (keyBag) || sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
- ASN1 safeBag = sb.ASN1;
-
- if (safeBag.Count == 3) {
- ASN1 bagAttributes = safeBag [2];
-
- int bagAttributesFound = 0;
- for (int i = 0; i < bagAttributes.Count; i++) {
- ASN1 pkcs12Attribute = bagAttributes [i];
- ASN1 attrId = pkcs12Attribute [0];
- string ao = ASN1Convert.ToOid (attrId);
- ArrayList dattrValues = (ArrayList)attrs [ao];
-
- if (dattrValues != null) {
- ASN1 attrValues = pkcs12Attribute [1];
-
- if (dattrValues.Count == attrValues.Count) {
- int attrValuesFound = 0;
- for (int j = 0; j < attrValues.Count; j++) {
- ASN1 attrValue = attrValues [j];
- byte[] value = (byte[])dattrValues [j];
-
- if (Compare (value, attrValue.Value)) {
- attrValuesFound += 1;
- }
- }
- if (attrValuesFound == attrValues.Count) {
- bagAttributesFound += 1;
- }
- }
- }
- }
- if (bagAttributesFound == bagAttributes.Count) {
- ASN1 bagValue = safeBag [1];
- AsymmetricAlgorithm aa = null;
- if (sb.BagOID.Equals (keyBag)) {
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
- byte[] privateKey = pki.PrivateKey;
- switch (privateKey [0]) {
- case 0x02:
- DSAParameters p = new DSAParameters (); // FIXME
- aa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
- break;
- case 0x30:
- aa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
- break;
- default:
- break;
- }
- Array.Clear (privateKey, 0, privateKey.Length);
- } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
- PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
- byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
- byte[] privateKey = pki.PrivateKey;
- switch (privateKey [0]) {
- case 0x02:
- DSAParameters p = new DSAParameters (); // FIXME
- aa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
- break;
- case 0x30:
- aa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
- break;
- default:
- break;
- }
- Array.Clear (privateKey, 0, privateKey.Length);
- Array.Clear (decrypted, 0, decrypted.Length);
- }
- return aa;
- }
- }
- }
- }
-
- return null;
- }
-
- public byte[] GetSecret (IDictionary attrs)
- {
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (secretBag)) {
- ASN1 safeBag = sb.ASN1;
-
- if (safeBag.Count == 3) {
- ASN1 bagAttributes = safeBag [2];
-
- int bagAttributesFound = 0;
- for (int i = 0; i < bagAttributes.Count; i++) {
- ASN1 pkcs12Attribute = bagAttributes [i];
- ASN1 attrId = pkcs12Attribute [0];
- string ao = ASN1Convert.ToOid (attrId);
- ArrayList dattrValues = (ArrayList)attrs [ao];
-
- if (dattrValues != null) {
- ASN1 attrValues = pkcs12Attribute [1];
-
- if (dattrValues.Count == attrValues.Count) {
- int attrValuesFound = 0;
- for (int j = 0; j < attrValues.Count; j++) {
- ASN1 attrValue = attrValues [j];
- byte[] value = (byte[])dattrValues [j];
-
- if (Compare (value, attrValue.Value)) {
- attrValuesFound += 1;
- }
- }
- if (attrValuesFound == attrValues.Count) {
- bagAttributesFound += 1;
- }
- }
- }
- }
- if (bagAttributesFound == bagAttributes.Count) {
- ASN1 bagValue = safeBag [1];
- return bagValue.Value;
- }
- }
- }
- }
-
- return null;
- }
-
- public X509Certificate GetCertificate (IDictionary attrs)
- {
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (certBag)) {
- ASN1 safeBag = sb.ASN1;
-
- if (safeBag.Count == 3) {
- ASN1 bagAttributes = safeBag [2];
-
- int bagAttributesFound = 0;
- for (int i = 0; i < bagAttributes.Count; i++) {
- ASN1 pkcs12Attribute = bagAttributes [i];
- ASN1 attrId = pkcs12Attribute [0];
- string ao = ASN1Convert.ToOid (attrId);
- ArrayList dattrValues = (ArrayList)attrs [ao];
-
- if (dattrValues != null) {
- ASN1 attrValues = pkcs12Attribute [1];
-
- if (dattrValues.Count == attrValues.Count) {
- int attrValuesFound = 0;
- for (int j = 0; j < attrValues.Count; j++) {
- ASN1 attrValue = attrValues [j];
- byte[] value = (byte[])dattrValues [j];
-
- if (Compare (value, attrValue.Value)) {
- attrValuesFound += 1;
- }
- }
- if (attrValuesFound == attrValues.Count) {
- bagAttributesFound += 1;
- }
- }
- }
- }
- if (bagAttributesFound == bagAttributes.Count) {
- ASN1 bagValue = safeBag [1];
- PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
- return new X509Certificate (crt.Content [0].Value);
- }
- }
- }
- }
-
- return null;
- }
-
- public IDictionary GetAttributes (AsymmetricAlgorithm aa)
- {
- IDictionary result = new Hashtable ();
-
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (keyBag) || sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
- ASN1 safeBag = sb.ASN1;
-
- ASN1 bagValue = safeBag [1];
- AsymmetricAlgorithm saa = null;
- if (sb.BagOID.Equals (keyBag)) {
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
- byte[] privateKey = pki.PrivateKey;
- switch (privateKey [0]) {
- case 0x02:
- DSAParameters p = new DSAParameters (); // FIXME
- saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
- break;
- case 0x30:
- saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
- break;
- default:
- break;
- }
- Array.Clear (privateKey, 0, privateKey.Length);
- } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
- PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
- byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
- PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
- byte[] privateKey = pki.PrivateKey;
- switch (privateKey [0]) {
- case 0x02:
- DSAParameters p = new DSAParameters (); // FIXME
- saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
- break;
- case 0x30:
- saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
- break;
- default:
- break;
- }
- Array.Clear (privateKey, 0, privateKey.Length);
- Array.Clear (decrypted, 0, decrypted.Length);
- }
-
- if (saa != null && CompareAsymmetricAlgorithm (saa, aa)) {
- if (safeBag.Count == 3) {
- ASN1 bagAttributes = safeBag [2];
-
- for (int i = 0; i < bagAttributes.Count; i++) {
- ASN1 pkcs12Attribute = bagAttributes [i];
- ASN1 attrId = pkcs12Attribute [0];
- string aOid = ASN1Convert.ToOid (attrId);
- ArrayList aValues = new ArrayList ();
-
- ASN1 attrValues = pkcs12Attribute [1];
-
- for (int j = 0; j < attrValues.Count; j++) {
- ASN1 attrValue = attrValues [j];
- aValues.Add (attrValue.Value);
- }
- result.Add (aOid, aValues);
- }
- }
- }
- }
- }
-
- return result;
- }
-
- public IDictionary GetAttributes (X509Certificate cert)
- {
- IDictionary result = new Hashtable ();
-
- foreach (SafeBag sb in _safeBags) {
- if (sb.BagOID.Equals (certBag)) {
- ASN1 safeBag = sb.ASN1;
- ASN1 bagValue = safeBag [1];
- PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
- X509Certificate xc = new X509Certificate (crt.Content [0].Value);
-
- if (Compare (cert.RawData, xc.RawData)) {
- if (safeBag.Count == 3) {
- ASN1 bagAttributes = safeBag [2];
-
- for (int i = 0; i < bagAttributes.Count; i++) {
- ASN1 pkcs12Attribute = bagAttributes [i];
- ASN1 attrId = pkcs12Attribute [0];
-
- string aOid = ASN1Convert.ToOid (attrId);
- ArrayList aValues = new ArrayList ();
-
- ASN1 attrValues = pkcs12Attribute [1];
-
- for (int j = 0; j < attrValues.Count; j++) {
- ASN1 attrValue = attrValues [j];
- aValues.Add (attrValue.Value);
- }
- result.Add (aOid, aValues);
- }
- }
- }
- }
- }
-
- return result;
- }
-
- public void SaveToFile (string filename)
- {
- if (filename == null)
- throw new ArgumentNullException ("filename");
-
- using (FileStream fs = File.Create (filename)) {
- byte[] data = GetBytes ();
- fs.Write (data, 0, data.Length);
- }
- }
-
- public object Clone ()
- {
- PKCS12 clone = null;
- if (_password != null) {
- clone = new PKCS12 (GetBytes (), Encoding.BigEndianUnicode.GetString (_password));
- } else {
- clone = new PKCS12 (GetBytes ());
- }
- clone.IterationCount = this.IterationCount;
-
- return clone;
- }
-
- // static
-
- public const int CryptoApiPasswordLimit = 32;
-
- static private int password_max_length = Int32.MaxValue;
-
- // static properties
-
- // MS CryptoAPI limits the password to a maximum of 31 characters
- // other implementations, like OpenSSL, have no such limitation.
- // Setting a maximum value will truncate the password length to
- // ensure compatibility with MS's PFXImportCertStore API.
- static public int MaximumPasswordLength {
- get { return password_max_length; }
- set {
- if (value < CryptoApiPasswordLimit) {
- string msg = string.Format ("Maximum password length cannot be less than {0}.", CryptoApiPasswordLimit);
- throw new ArgumentOutOfRangeException (msg);
- }
- password_max_length = value;
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/PKCS7.cs b/Emby.Server.Implementations/Cryptography/PKCS7.cs
deleted file mode 100644
index 475854500..000000000
--- a/Emby.Server.Implementations/Cryptography/PKCS7.cs
+++ /dev/null
@@ -1,1012 +0,0 @@
-//
-// PKCS7.cs: PKCS #7 - Cryptographic Message Syntax Standard
-// http://www.rsasecurity.com/rsalabs/pkcs/pkcs-7/index.html
-//
-// Authors:
-// Sebastien Pouliot <sebastien@ximian.com>
-// Daniel Granath <dgranath#gmail.com>
-//
-// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Collections;
-using System.Security.Cryptography;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- public sealed class PKCS7 {
-
- public class Oid {
- // pkcs 1
- public const string rsaEncryption = "1.2.840.113549.1.1.1";
- // pkcs 7
- public const string data = "1.2.840.113549.1.7.1";
- public const string signedData = "1.2.840.113549.1.7.2";
- public const string envelopedData = "1.2.840.113549.1.7.3";
- public const string signedAndEnvelopedData = "1.2.840.113549.1.7.4";
- public const string digestedData = "1.2.840.113549.1.7.5";
- public const string encryptedData = "1.2.840.113549.1.7.6";
- // pkcs 9
- public const string contentType = "1.2.840.113549.1.9.3";
- public const string messageDigest = "1.2.840.113549.1.9.4";
- public const string signingTime = "1.2.840.113549.1.9.5";
- public const string countersignature = "1.2.840.113549.1.9.6";
-
- public Oid ()
- {
- }
- }
-
- private PKCS7 ()
- {
- }
-
- static public ASN1 Attribute (string oid, ASN1 value)
- {
- ASN1 attr = new ASN1 (0x30);
- attr.Add (ASN1Convert.FromOid (oid));
- ASN1 aset = attr.Add (new ASN1 (0x31));
- aset.Add (value);
- return attr;
- }
-
- static public ASN1 AlgorithmIdentifier (string oid)
- {
- ASN1 ai = new ASN1 (0x30);
- ai.Add (ASN1Convert.FromOid (oid));
- ai.Add (new ASN1 (0x05)); // NULL
- return ai;
- }
-
- static public ASN1 AlgorithmIdentifier (string oid, ASN1 parameters)
- {
- ASN1 ai = new ASN1 (0x30);
- ai.Add (ASN1Convert.FromOid (oid));
- ai.Add (parameters);
- return ai;
- }
-
- /*
- * IssuerAndSerialNumber ::= SEQUENCE {
- * issuer Name,
- * serialNumber CertificateSerialNumber
- * }
- */
- static public ASN1 IssuerAndSerialNumber (X509Certificate x509)
- {
- ASN1 issuer = null;
- ASN1 serial = null;
- ASN1 cert = new ASN1 (x509.RawData);
- int tbs = 0;
- bool flag = false;
- while (tbs < cert[0].Count) {
- ASN1 e = cert[0][tbs++];
- if (e.Tag == 0x02)
- serial = e;
- else if (e.Tag == 0x30) {
- if (flag) {
- issuer = e;
- break;
- }
- flag = true;
- }
- }
- ASN1 iasn = new ASN1 (0x30);
- iasn.Add (issuer);
- iasn.Add (serial);
- return iasn;
- }
-
- /*
- * ContentInfo ::= SEQUENCE {
- * contentType ContentType,
- * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
- * }
- * ContentType ::= OBJECT IDENTIFIER
- */
- public class ContentInfo {
-
- private string contentType;
- private ASN1 content;
-
- public ContentInfo ()
- {
- content = new ASN1 (0xA0);
- }
-
- public ContentInfo (string oid) : this ()
- {
- contentType = oid;
- }
-
- public ContentInfo (byte[] data)
- : this (new ASN1 (data)) {}
-
- public ContentInfo (ASN1 asn1)
- {
- // SEQUENCE with 1 or 2 elements
- if ((asn1.Tag != 0x30) || ((asn1.Count < 1) && (asn1.Count > 2)))
- throw new ArgumentException ("Invalid ASN1");
- if (asn1[0].Tag != 0x06)
- throw new ArgumentException ("Invalid contentType");
- contentType = ASN1Convert.ToOid (asn1[0]);
- if (asn1.Count > 1) {
- if (asn1[1].Tag != 0xA0)
- throw new ArgumentException ("Invalid content");
- content = asn1[1];
- }
- }
-
- public ASN1 ASN1 {
- get { return GetASN1(); }
- }
-
- public ASN1 Content {
- get { return content; }
- set { content = value; }
- }
-
- public string ContentType {
- get { return contentType; }
- set { contentType = value; }
- }
-
- internal ASN1 GetASN1 ()
- {
- // ContentInfo ::= SEQUENCE {
- ASN1 contentInfo = new ASN1 (0x30);
- // contentType ContentType, -> ContentType ::= OBJECT IDENTIFIER
- contentInfo.Add (ASN1Convert.FromOid (contentType));
- // content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
- if ((content != null) && (content.Count > 0))
- contentInfo.Add (content);
- return contentInfo;
- }
-
- public byte[] GetBytes ()
- {
- return GetASN1 ().GetBytes ();
- }
- }
-
- /*
- * EncryptedData ::= SEQUENCE {
- * version INTEGER {edVer0(0)} (edVer0),
- * encryptedContentInfo EncryptedContentInfo
- * }
- */
- public class EncryptedData {
- private byte _version;
- private ContentInfo _content;
- private ContentInfo _encryptionAlgorithm;
- private byte[] _encrypted;
-
- public EncryptedData ()
- {
- _version = 0;
- }
-
- public EncryptedData (byte[] data)
- : this (new ASN1 (data))
- {
- }
-
- public EncryptedData (ASN1 asn1) : this ()
- {
- if ((asn1.Tag != 0x30) || (asn1.Count < 2))
- throw new ArgumentException ("Invalid EncryptedData");
-
- if (asn1 [0].Tag != 0x02)
- throw new ArgumentException ("Invalid version");
- _version = asn1 [0].Value [0];
-
- ASN1 encryptedContentInfo = asn1 [1];
- if (encryptedContentInfo.Tag != 0x30)
- throw new ArgumentException ("missing EncryptedContentInfo");
-
- ASN1 contentType = encryptedContentInfo [0];
- if (contentType.Tag != 0x06)
- throw new ArgumentException ("missing EncryptedContentInfo.ContentType");
- _content = new ContentInfo (ASN1Convert.ToOid (contentType));
-
- ASN1 contentEncryptionAlgorithm = encryptedContentInfo [1];
- if (contentEncryptionAlgorithm.Tag != 0x30)
- throw new ArgumentException ("missing EncryptedContentInfo.ContentEncryptionAlgorithmIdentifier");
- _encryptionAlgorithm = new ContentInfo (ASN1Convert.ToOid (contentEncryptionAlgorithm [0]));
- _encryptionAlgorithm.Content = contentEncryptionAlgorithm [1];
-
- ASN1 encryptedContent = encryptedContentInfo [2];
- if (encryptedContent.Tag != 0x80)
- throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent");
- _encrypted = encryptedContent.Value;
- }
-
- public ASN1 ASN1 {
- get { return GetASN1(); }
- }
-
- public ContentInfo ContentInfo {
- get { return _content; }
- }
-
- public ContentInfo EncryptionAlgorithm {
- get { return _encryptionAlgorithm; }
- }
-
- public byte[] EncryptedContent {
- get {
- if (_encrypted == null)
- return null;
- return (byte[]) _encrypted.Clone ();
- }
- }
-
- public byte Version {
- get { return _version; }
- set { _version = value; }
- }
-
- // methods
-
- internal ASN1 GetASN1 ()
- {
- return null;
- }
-
- public byte[] GetBytes ()
- {
- return GetASN1 ().GetBytes ();
- }
- }
-
- /*
- * EnvelopedData ::= SEQUENCE {
- * version Version,
- * recipientInfos RecipientInfos,
- * encryptedContentInfo EncryptedContentInfo
- * }
- *
- * RecipientInfos ::= SET OF RecipientInfo
- *
- * EncryptedContentInfo ::= SEQUENCE {
- * contentType ContentType,
- * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
- * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
- * }
- *
- * EncryptedContent ::= OCTET STRING
- *
- */
- public class EnvelopedData {
- private byte _version;
- private ContentInfo _content;
- private ContentInfo _encryptionAlgorithm;
- private ArrayList _recipientInfos;
- private byte[] _encrypted;
-
- public EnvelopedData ()
- {
- _version = 0;
- _content = new ContentInfo ();
- _encryptionAlgorithm = new ContentInfo ();
- _recipientInfos = new ArrayList ();
- }
-
- public EnvelopedData (byte[] data)
- : this (new ASN1 (data))
- {
- }
-
- public EnvelopedData (ASN1 asn1) : this ()
- {
- if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 3))
- throw new ArgumentException ("Invalid EnvelopedData");
-
- if (asn1[0][0].Tag != 0x02)
- throw new ArgumentException ("Invalid version");
- _version = asn1[0][0].Value[0];
-
- // recipientInfos
-
- ASN1 recipientInfos = asn1 [0][1];
- if (recipientInfos.Tag != 0x31)
- throw new ArgumentException ("missing RecipientInfos");
- for (int i=0; i < recipientInfos.Count; i++) {
- ASN1 recipientInfo = recipientInfos [i];
- _recipientInfos.Add (new RecipientInfo (recipientInfo));
- }
-
- ASN1 encryptedContentInfo = asn1[0][2];
- if (encryptedContentInfo.Tag != 0x30)
- throw new ArgumentException ("missing EncryptedContentInfo");
-
- ASN1 contentType = encryptedContentInfo [0];
- if (contentType.Tag != 0x06)
- throw new ArgumentException ("missing EncryptedContentInfo.ContentType");
- _content = new ContentInfo (ASN1Convert.ToOid (contentType));
-
- ASN1 contentEncryptionAlgorithm = encryptedContentInfo [1];
- if (contentEncryptionAlgorithm.Tag != 0x30)
- throw new ArgumentException ("missing EncryptedContentInfo.ContentEncryptionAlgorithmIdentifier");
- _encryptionAlgorithm = new ContentInfo (ASN1Convert.ToOid (contentEncryptionAlgorithm [0]));
- _encryptionAlgorithm.Content = contentEncryptionAlgorithm [1];
-
- ASN1 encryptedContent = encryptedContentInfo [2];
- if (encryptedContent.Tag != 0x80)
- throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent");
- _encrypted = encryptedContent.Value;
- }
-
- public ArrayList RecipientInfos {
- get { return _recipientInfos; }
- }
-
- public ASN1 ASN1 {
- get { return GetASN1(); }
- }
-
- public ContentInfo ContentInfo {
- get { return _content; }
- }
-
- public ContentInfo EncryptionAlgorithm {
- get { return _encryptionAlgorithm; }
- }
-
- public byte[] EncryptedContent {
- get {
- if (_encrypted == null)
- return null;
- return (byte[]) _encrypted.Clone ();
- }
- }
-
- public byte Version {
- get { return _version; }
- set { _version = value; }
- }
-
- internal ASN1 GetASN1 ()
- {
- // SignedData ::= SEQUENCE {
- ASN1 signedData = new ASN1 (0x30);
- // version Version -> Version ::= INTEGER
-/* byte[] ver = { _version };
- signedData.Add (new ASN1 (0x02, ver));
- // digestAlgorithms DigestAlgorithmIdentifiers -> DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
- ASN1 digestAlgorithms = signedData.Add (new ASN1 (0x31));
- if (hashAlgorithm != null) {
- string hashOid = CryptoConfig.MapNameToOid (hashAlgorithm);
- digestAlgorithms.Add (AlgorithmIdentifier (hashOid));
- }
-
- // contentInfo ContentInfo,
- ASN1 ci = contentInfo.ASN1;
- signedData.Add (ci);
- if ((mda == null) && (hashAlgorithm != null)) {
- // automatically add the messageDigest authenticated attribute
- HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
- byte[] idcHash = ha.ComputeHash (ci[1][0].Value);
- ASN1 md = new ASN1 (0x30);
- mda = Attribute (messageDigest, md.Add (new ASN1 (0x04, idcHash)));
- signerInfo.AuthenticatedAttributes.Add (mda);
- }
-
- // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
- if (certs.Count > 0) {
- ASN1 a0 = signedData.Add (new ASN1 (0xA0));
- foreach (X509Certificate x in certs)
- a0.Add (new ASN1 (x.RawData));
- }
- // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
- if (crls.Count > 0) {
- ASN1 a1 = signedData.Add (new ASN1 (0xA1));
- foreach (byte[] crl in crls)
- a1.Add (new ASN1 (crl));
- }
- // signerInfos SignerInfos -> SignerInfos ::= SET OF SignerInfo
- ASN1 signerInfos = signedData.Add (new ASN1 (0x31));
- if (signerInfo.Key != null)
- signerInfos.Add (signerInfo.ASN1);*/
- return signedData;
- }
-
- public byte[] GetBytes () {
- return GetASN1 ().GetBytes ();
- }
- }
-
- /* RecipientInfo ::= SEQUENCE {
- * version Version,
- * issuerAndSerialNumber IssuerAndSerialNumber,
- * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
- * encryptedKey EncryptedKey
- * }
- *
- * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
- *
- * EncryptedKey ::= OCTET STRING
- */
- public class RecipientInfo {
-
- private int _version;
- private string _oid;
- private byte[] _key;
- private byte[] _ski;
- private string _issuer;
- private byte[] _serial;
-
- public RecipientInfo () {}
-
- public RecipientInfo (ASN1 data)
- {
- if (data.Tag != 0x30)
- throw new ArgumentException ("Invalid RecipientInfo");
-
- ASN1 version = data [0];
- if (version.Tag != 0x02)
- throw new ArgumentException ("missing Version");
- _version = version.Value [0];
-
- // issuerAndSerialNumber IssuerAndSerialNumber
- ASN1 subjectIdentifierType = data [1];
- if ((subjectIdentifierType.Tag == 0x80) && (_version == 3)) {
- _ski = subjectIdentifierType.Value;
- }
- else {
- _issuer = X501.ToString (subjectIdentifierType [0]);
- _serial = subjectIdentifierType [1].Value;
- }
-
- ASN1 keyEncryptionAlgorithm = data [2];
- _oid = ASN1Convert.ToOid (keyEncryptionAlgorithm [0]);
-
- ASN1 encryptedKey = data [3];
- _key = encryptedKey.Value;
- }
-
- public string Oid {
- get { return _oid; }
- }
-
- public byte[] Key {
- get {
- if (_key == null)
- return null;
- return (byte[]) _key.Clone ();
- }
- }
-
- public byte[] SubjectKeyIdentifier {
- get {
- if (_ski == null)
- return null;
- return (byte[]) _ski.Clone ();
- }
- }
-
- public string Issuer {
- get { return _issuer; }
- }
-
- public byte[] Serial {
- get {
- if (_serial == null)
- return null;
- return (byte[]) _serial.Clone ();
- }
- }
-
- public int Version {
- get { return _version; }
- }
- }
-
- /*
- * SignedData ::= SEQUENCE {
- * version Version,
- * digestAlgorithms DigestAlgorithmIdentifiers,
- * contentInfo ContentInfo,
- * certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
- * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
- * signerInfos SignerInfos
- * }
- */
- public class SignedData {
- private byte version;
- private string hashAlgorithm;
- private ContentInfo contentInfo;
- private X509CertificateCollection certs;
- private ArrayList crls;
- private SignerInfo signerInfo;
- private bool mda;
- private bool signed;
-
- public SignedData ()
- {
- version = 1;
- contentInfo = new ContentInfo ();
- certs = new X509CertificateCollection ();
- crls = new ArrayList ();
- signerInfo = new SignerInfo ();
- mda = true;
- signed = false;
- }
-
- public SignedData (byte[] data)
- : this (new ASN1 (data))
- {
- }
-
- public SignedData (ASN1 asn1)
- {
- if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 4))
- throw new ArgumentException ("Invalid SignedData");
-
- if (asn1[0][0].Tag != 0x02)
- throw new ArgumentException ("Invalid version");
- version = asn1[0][0].Value[0];
-
- contentInfo = new ContentInfo (asn1[0][2]);
-
- int n = 3;
- certs = new X509CertificateCollection ();
- if (asn1[0][n].Tag == 0xA0) {
- for (int i=0; i < asn1[0][n].Count; i++)
- certs.Add (new X509Certificate (asn1[0][n][i].GetBytes ()));
- n++;
- }
-
- crls = new ArrayList ();
- if (asn1[0][n].Tag == 0xA1) {
- for (int i=0; i < asn1[0][n].Count; i++)
- crls.Add (asn1[0][n][i].GetBytes ());
- n++;
- }
-
- if (asn1[0][n].Count > 0)
- signerInfo = new SignerInfo (asn1[0][n]);
- else
- signerInfo = new SignerInfo ();
-
- // Exchange hash algorithm Oid from SignerInfo
- if (signerInfo.HashName != null) {
- HashName = OidToName(signerInfo.HashName);
- }
-
- // Check if SignerInfo has authenticated attributes
- mda = (signerInfo.AuthenticatedAttributes.Count > 0);
- }
-
- public ASN1 ASN1 {
- get { return GetASN1(); }
- }
-
- public X509CertificateCollection Certificates {
- get { return certs; }
- }
-
- public ContentInfo ContentInfo {
- get { return contentInfo; }
- }
-
- public ArrayList Crls {
- get { return crls; }
- }
-
- public string HashName {
- get { return hashAlgorithm; }
- // todo add validation
- set {
- hashAlgorithm = value;
- signerInfo.HashName = value;
- }
- }
-
- public SignerInfo SignerInfo {
- get { return signerInfo; }
- }
-
- public byte Version {
- get { return version; }
- set { version = value; }
- }
-
- public bool UseAuthenticatedAttributes {
- get { return mda; }
- set { mda = value; }
- }
-
- public bool VerifySignature (AsymmetricAlgorithm aa)
- {
- if (aa == null) {
- return false;
- }
-
- RSAPKCS1SignatureDeformatter r = new RSAPKCS1SignatureDeformatter (aa);
- r.SetHashAlgorithm (hashAlgorithm);
- HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
-
- byte[] signature = signerInfo.Signature;
- byte[] hash = null;
-
- if (mda) {
- ASN1 asn = new ASN1 (0x31);
- foreach (ASN1 attr in signerInfo.AuthenticatedAttributes)
- asn.Add (attr);
-
- hash = ha.ComputeHash (asn.GetBytes ());
- } else {
- hash = ha.ComputeHash (contentInfo.Content[0].Value);
- }
-
- if (hash != null && signature != null) {
- return r.VerifySignature (hash, signature);
- }
- return false;
- }
-
- internal string OidToName (string oid)
- {
- switch (oid) {
- case "1.3.14.3.2.26" :
- return "SHA1";
- case "1.2.840.113549.2.2" :
- return "MD2";
- case "1.2.840.113549.2.5" :
- return "MD5";
- case "2.16.840.1.101.3.4.1" :
- return "SHA256";
- case "2.16.840.1.101.3.4.2" :
- return "SHA384";
- case "2.16.840.1.101.3.4.3" :
- return "SHA512";
- default :
- break;
- }
- // Unknown Oid
- return oid;
- }
-
- internal ASN1 GetASN1 ()
- {
- // SignedData ::= SEQUENCE {
- ASN1 signedData = new ASN1 (0x30);
- // version Version -> Version ::= INTEGER
- byte[] ver = { version };
- signedData.Add (new ASN1 (0x02, ver));
- // digestAlgorithms DigestAlgorithmIdentifiers -> DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
- ASN1 digestAlgorithms = signedData.Add (new ASN1 (0x31));
- if (hashAlgorithm != null) {
- string hashOid = CryptoConfig.MapNameToOID (hashAlgorithm);
- digestAlgorithms.Add (AlgorithmIdentifier (hashOid));
- }
-
- // contentInfo ContentInfo,
- ASN1 ci = contentInfo.ASN1;
- signedData.Add (ci);
- if (!signed && (hashAlgorithm != null)) {
- if (mda) {
- // Use authenticated attributes for signature
-
- // Automatically add the contentType authenticated attribute
- ASN1 ctattr = Attribute (Oid.contentType, ci[0]);
- signerInfo.AuthenticatedAttributes.Add (ctattr);
-
- // Automatically add the messageDigest authenticated attribute
- HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
- byte[] idcHash = ha.ComputeHash (ci[1][0].Value);
- ASN1 md = new ASN1 (0x30);
- ASN1 mdattr = Attribute (Oid.messageDigest, md.Add (new ASN1 (0x04, idcHash)));
- signerInfo.AuthenticatedAttributes.Add (mdattr);
- } else {
- // Don't use authenticated attributes for signature -- signature is content
- RSAPKCS1SignatureFormatter r = new RSAPKCS1SignatureFormatter (signerInfo.Key);
- r.SetHashAlgorithm (hashAlgorithm);
- HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
- byte[] sig = ha.ComputeHash (ci[1][0].Value);
- signerInfo.Signature = r.CreateSignature (sig);
- }
- signed = true;
- }
-
- // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
- if (certs.Count > 0) {
- ASN1 a0 = signedData.Add (new ASN1 (0xA0));
- foreach (X509Certificate x in certs)
- a0.Add (new ASN1 (x.RawData));
- }
- // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
- if (crls.Count > 0) {
- ASN1 a1 = signedData.Add (new ASN1 (0xA1));
- foreach (byte[] crl in crls)
- a1.Add (new ASN1 (crl));
- }
- // signerInfos SignerInfos -> SignerInfos ::= SET OF SignerInfo
- ASN1 signerInfos = signedData.Add (new ASN1 (0x31));
- if (signerInfo.Key != null)
- signerInfos.Add (signerInfo.ASN1);
- return signedData;
- }
-
- public byte[] GetBytes ()
- {
- return GetASN1 ().GetBytes ();
- }
- }
-
- /*
- * SignerInfo ::= SEQUENCE {
- * version Version,
- * issuerAndSerialNumber IssuerAndSerialNumber,
- * digestAlgorithm DigestAlgorithmIdentifier,
- * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
- * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
- * encryptedDigest EncryptedDigest,
- * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
- * }
- *
- * For version == 3 issuerAndSerialNumber may be replaced by ...
- */
- public class SignerInfo {
-
- private byte version;
- private X509Certificate x509;
- private string hashAlgorithm;
- private AsymmetricAlgorithm key;
- private ArrayList authenticatedAttributes;
- private ArrayList unauthenticatedAttributes;
- private byte[] signature;
- private string issuer;
- private byte[] serial;
- private byte[] ski;
-
- public SignerInfo ()
- {
- version = 1;
- authenticatedAttributes = new ArrayList ();
- unauthenticatedAttributes = new ArrayList ();
- }
-
- public SignerInfo (byte[] data)
- : this (new ASN1 (data)) {}
-
- // TODO: INCOMPLETE
- public SignerInfo (ASN1 asn1) : this ()
- {
- if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 5))
- throw new ArgumentException ("Invalid SignedData");
-
- // version Version
- if (asn1[0][0].Tag != 0x02)
- throw new ArgumentException ("Invalid version");
- version = asn1[0][0].Value[0];
-
- // issuerAndSerialNumber IssuerAndSerialNumber
- ASN1 subjectIdentifierType = asn1 [0][1];
- if ((subjectIdentifierType.Tag == 0x80) && (version == 3)) {
- ski = subjectIdentifierType.Value;
- }
- else {
- issuer = X501.ToString (subjectIdentifierType [0]);
- serial = subjectIdentifierType [1].Value;
- }
-
- // digestAlgorithm DigestAlgorithmIdentifier
- ASN1 digestAlgorithm = asn1 [0][2];
- hashAlgorithm = ASN1Convert.ToOid (digestAlgorithm [0]);
-
- // authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL
- int n = 3;
- ASN1 authAttributes = asn1 [0][n];
- if (authAttributes.Tag == 0xA0) {
- n++;
- for (int i=0; i < authAttributes.Count; i++)
- authenticatedAttributes.Add (authAttributes [i]);
- }
-
- // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier
- n++;
- // ASN1 digestEncryptionAlgorithm = asn1 [0][n++];
- // string digestEncryptionAlgorithmOid = ASN1Convert.ToOid (digestEncryptionAlgorithm [0]);
-
- // encryptedDigest EncryptedDigest
- ASN1 encryptedDigest = asn1 [0][n++];
- if (encryptedDigest.Tag == 0x04)
- signature = encryptedDigest.Value;
-
- // unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
- ASN1 unauthAttributes = asn1 [0][n];
- if ((unauthAttributes != null) && (unauthAttributes.Tag == 0xA1)) {
- for (int i=0; i < unauthAttributes.Count; i++)
- unauthenticatedAttributes.Add (unauthAttributes [i]);
- }
- }
-
- public string IssuerName {
- get { return issuer; }
- }
-
- public byte[] SerialNumber {
- get {
- if (serial == null)
- return null;
- return (byte[]) serial.Clone ();
- }
- }
-
- public byte[] SubjectKeyIdentifier {
- get {
- if (ski == null)
- return null;
- return (byte[]) ski.Clone ();
- }
- }
-
- public ASN1 ASN1 {
- get { return GetASN1(); }
- }
-
- public ArrayList AuthenticatedAttributes {
- get { return authenticatedAttributes; }
- }
-
- public X509Certificate Certificate {
- get { return x509; }
- set { x509 = value; }
- }
-
- public string HashName {
- get { return hashAlgorithm; }
- set { hashAlgorithm = value; }
- }
-
- public AsymmetricAlgorithm Key {
- get { return key; }
- set { key = value; }
- }
-
- public byte[] Signature {
- get {
- if (signature == null)
- return null;
- return (byte[]) signature.Clone ();
- }
-
- set {
- if (value != null) {
- signature = (byte[]) value.Clone ();
- }
- }
- }
-
- public ArrayList UnauthenticatedAttributes {
- get { return unauthenticatedAttributes; }
- }
-
- public byte Version {
- get { return version; }
- set { version = value; }
- }
-
- internal ASN1 GetASN1 ()
- {
- if ((key == null) || (hashAlgorithm == null))
- return null;
- byte[] ver = { version };
- ASN1 signerInfo = new ASN1 (0x30);
- // version Version -> Version ::= INTEGER
- signerInfo.Add (new ASN1 (0x02, ver));
- // issuerAndSerialNumber IssuerAndSerialNumber,
- signerInfo.Add (PKCS7.IssuerAndSerialNumber (x509));
- // digestAlgorithm DigestAlgorithmIdentifier,
- string hashOid = CryptoConfig.MapNameToOID (hashAlgorithm);
- signerInfo.Add (AlgorithmIdentifier (hashOid));
- // authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
- ASN1 aa = null;
- if (authenticatedAttributes.Count > 0) {
- aa = signerInfo.Add (new ASN1 (0xA0));
- authenticatedAttributes.Sort(new SortedSet ());
- foreach (ASN1 attr in authenticatedAttributes)
- aa.Add (attr);
- }
- // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
- if (key is RSA) {
- signerInfo.Add (AlgorithmIdentifier (PKCS7.Oid.rsaEncryption));
-
- if (aa != null) {
- // Calculate the signature here; otherwise it must be set from SignedData
- RSAPKCS1SignatureFormatter r = new RSAPKCS1SignatureFormatter (key);
- r.SetHashAlgorithm (hashAlgorithm);
- byte[] tbs = aa.GetBytes ();
- tbs [0] = 0x31; // not 0xA0 for signature
- HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
- byte[] tbsHash = ha.ComputeHash (tbs);
- signature = r.CreateSignature (tbsHash);
- }
- }
- else if (key is DSA) {
- throw new NotImplementedException ("not yet");
- }
- else
- throw new CryptographicException ("Unknown assymetric algorithm");
- // encryptedDigest EncryptedDigest,
- signerInfo.Add (new ASN1 (0x04, signature));
- // unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
- if (unauthenticatedAttributes.Count > 0) {
- ASN1 ua = signerInfo.Add (new ASN1 (0xA1));
- unauthenticatedAttributes.Sort(new SortedSet ());
- foreach (ASN1 attr in unauthenticatedAttributes)
- ua.Add (attr);
- }
- return signerInfo;
- }
-
- public byte[] GetBytes ()
- {
- return GetASN1 ().GetBytes ();
- }
- }
-
- internal class SortedSet : IComparer {
-
- public int Compare (object x, object y)
- {
- if (x == null)
- return (y == null) ? 0 : -1;
- else if (y == null)
- return 1;
-
- ASN1 xx = x as ASN1;
- ASN1 yy = y as ASN1;
-
- if ((xx == null) || (yy == null)) {
- throw new ArgumentException (("Invalid objects."));
- }
-
- byte[] xb = xx.GetBytes ();
- byte[] yb = yy.GetBytes ();
-
- for (int i = 0; i < xb.Length; i++) {
- if (i == yb.Length)
- break;
-
- if (xb[i] == yb[i])
- continue;
-
- return (xb[i] < yb[i]) ? -1 : 1;
- }
-
- // The arrays are equal up to the shortest of them.
- if (xb.Length > yb.Length)
- return 1;
- else if (xb.Length < yb.Length)
- return -1;
-
- return 0;
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/PKCS8.cs b/Emby.Server.Implementations/Cryptography/PKCS8.cs
deleted file mode 100644
index 7e9a27298..000000000
--- a/Emby.Server.Implementations/Cryptography/PKCS8.cs
+++ /dev/null
@@ -1,495 +0,0 @@
-//
-// PKCS8.cs: PKCS #8 - Private-Key Information Syntax Standard
-// ftp://ftp.rsasecurity.com/pub/pkcs/doc/pkcs-8.doc
-//
-// Author:
-// Sebastien Pouliot <sebastien@xamarin.com>
-//
-// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
-// Copyright 2013 Xamarin Inc. (http://www.xamarin.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Collections;
-using System.Security.Cryptography;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- public sealed class PKCS8 {
-
- public enum KeyInfo {
- PrivateKey,
- EncryptedPrivateKey,
- Unknown
- }
-
- private PKCS8 ()
- {
- }
-
- static public KeyInfo GetType (byte[] data)
- {
- if (data == null)
- throw new ArgumentNullException ("data");
-
- KeyInfo ki = KeyInfo.Unknown;
- try {
- ASN1 top = new ASN1 (data);
- if ((top.Tag == 0x30) && (top.Count > 0)) {
- ASN1 firstLevel = top [0];
- switch (firstLevel.Tag) {
- case 0x02:
- ki = KeyInfo.PrivateKey;
- break;
- case 0x30:
- ki = KeyInfo.EncryptedPrivateKey;
- break;
- }
- }
- }
- catch {
- throw new CryptographicException ("invalid ASN.1 data");
- }
- return ki;
- }
-
- /*
- * PrivateKeyInfo ::= SEQUENCE {
- * version Version,
- * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
- * privateKey PrivateKey,
- * attributes [0] IMPLICIT Attributes OPTIONAL
- * }
- *
- * Version ::= INTEGER
- *
- * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
- *
- * PrivateKey ::= OCTET STRING
- *
- * Attributes ::= SET OF Attribute
- */
- public class PrivateKeyInfo {
-
- private int _version;
- private string _algorithm;
- private byte[] _key;
- private ArrayList _list;
-
- public PrivateKeyInfo ()
- {
- _version = 0;
- _list = new ArrayList ();
- }
-
- public PrivateKeyInfo (byte[] data) : this ()
- {
- Decode (data);
- }
-
- // properties
-
- public string Algorithm {
- get { return _algorithm; }
- set { _algorithm = value; }
- }
-
- public ArrayList Attributes {
- get { return _list; }
- }
-
- public byte[] PrivateKey {
- get {
- if (_key == null)
- return null;
- return (byte[]) _key.Clone ();
- }
- set {
- if (value == null)
- throw new ArgumentNullException ("PrivateKey");
- _key = (byte[]) value.Clone ();
- }
- }
-
- public int Version {
- get { return _version; }
- set {
- if (value < 0)
- throw new ArgumentOutOfRangeException ("negative version");
- _version = value;
- }
- }
-
- // methods
-
- private void Decode (byte[] data)
- {
- ASN1 privateKeyInfo = new ASN1 (data);
- if (privateKeyInfo.Tag != 0x30)
- throw new CryptographicException ("invalid PrivateKeyInfo");
-
- ASN1 version = privateKeyInfo [0];
- if (version.Tag != 0x02)
- throw new CryptographicException ("invalid version");
- _version = version.Value [0];
-
- ASN1 privateKeyAlgorithm = privateKeyInfo [1];
- if (privateKeyAlgorithm.Tag != 0x30)
- throw new CryptographicException ("invalid algorithm");
-
- ASN1 algorithm = privateKeyAlgorithm [0];
- if (algorithm.Tag != 0x06)
- throw new CryptographicException ("missing algorithm OID");
- _algorithm = ASN1Convert.ToOid (algorithm);
-
- ASN1 privateKey = privateKeyInfo [2];
- _key = privateKey.Value;
-
- // attributes [0] IMPLICIT Attributes OPTIONAL
- if (privateKeyInfo.Count > 3) {
- ASN1 attributes = privateKeyInfo [3];
- for (int i=0; i < attributes.Count; i++) {
- _list.Add (attributes [i]);
- }
- }
- }
-
- public byte[] GetBytes ()
- {
- ASN1 privateKeyAlgorithm = new ASN1 (0x30);
- privateKeyAlgorithm.Add (ASN1Convert.FromOid (_algorithm));
- privateKeyAlgorithm.Add (new ASN1 (0x05)); // ASN.1 NULL
-
- ASN1 pki = new ASN1 (0x30);
- pki.Add (new ASN1 (0x02, new byte [1] { (byte) _version }));
- pki.Add (privateKeyAlgorithm);
- pki.Add (new ASN1 (0x04, _key));
-
- if (_list.Count > 0) {
- ASN1 attributes = new ASN1 (0xA0);
- foreach (ASN1 attribute in _list) {
- attributes.Add (attribute);
- }
- pki.Add (attributes);
- }
-
- return pki.GetBytes ();
- }
-
- // static methods
-
- static private byte[] RemoveLeadingZero (byte[] bigInt)
- {
- int start = 0;
- int length = bigInt.Length;
- if (bigInt [0] == 0x00) {
- start = 1;
- length--;
- }
- byte[] bi = new byte [length];
- Buffer.BlockCopy (bigInt, start, bi, 0, length);
- return bi;
- }
-
- static private byte[] Normalize (byte[] bigInt, int length)
- {
- if (bigInt.Length == length)
- return bigInt;
- else if (bigInt.Length > length)
- return RemoveLeadingZero (bigInt);
- else {
- // pad with 0
- byte[] bi = new byte [length];
- Buffer.BlockCopy (bigInt, 0, bi, (length - bigInt.Length), bigInt.Length);
- return bi;
- }
- }
-
- /*
- * RSAPrivateKey ::= SEQUENCE {
- * version Version,
- * modulus INTEGER, -- n
- * publicExponent INTEGER, -- e
- * privateExponent INTEGER, -- d
- * prime1 INTEGER, -- p
- * prime2 INTEGER, -- q
- * exponent1 INTEGER, -- d mod (p-1)
- * exponent2 INTEGER, -- d mod (q-1)
- * coefficient INTEGER, -- (inverse of q) mod p
- * otherPrimeInfos OtherPrimeInfos OPTIONAL
- * }
- */
- static public RSA DecodeRSA (byte[] keypair)
- {
- ASN1 privateKey = new ASN1 (keypair);
- if (privateKey.Tag != 0x30)
- throw new CryptographicException ("invalid private key format");
-
- ASN1 version = privateKey [0];
- if (version.Tag != 0x02)
- throw new CryptographicException ("missing version");
-
- if (privateKey.Count < 9)
- throw new CryptographicException ("not enough key parameters");
-
- RSAParameters param = new RSAParameters ();
- // note: MUST remove leading 0 - else MS wont import the key
- param.Modulus = RemoveLeadingZero (privateKey [1].Value);
- int keysize = param.Modulus.Length;
- int keysize2 = (keysize >> 1); // half-size
- // size must be normalized - else MS wont import the key
- param.D = Normalize (privateKey [3].Value, keysize);
- param.DP = Normalize (privateKey [6].Value, keysize2);
- param.DQ = Normalize (privateKey [7].Value, keysize2);
- param.Exponent = RemoveLeadingZero (privateKey [2].Value);
- param.InverseQ = Normalize (privateKey [8].Value, keysize2);
- param.P = Normalize (privateKey [4].Value, keysize2);
- param.Q = Normalize (privateKey [5].Value, keysize2);
-
- RSA rsa = null;
- try {
- rsa = RSA.Create ();
- rsa.ImportParameters (param);
- }
- catch (CryptographicException) {
- // this may cause problem when this code is run under
- // the SYSTEM identity on Windows (e.g. ASP.NET). See
- // http://bugzilla.ximian.com/show_bug.cgi?id=77559
- CspParameters csp = new CspParameters();
- csp.Flags = CspProviderFlags.UseMachineKeyStore;
- rsa = new RSACryptoServiceProvider(csp);
- rsa.ImportParameters(param);
- }
- return rsa;
- }
-
- /*
- * RSAPrivateKey ::= SEQUENCE {
- * version Version,
- * modulus INTEGER, -- n
- * publicExponent INTEGER, -- e
- * privateExponent INTEGER, -- d
- * prime1 INTEGER, -- p
- * prime2 INTEGER, -- q
- * exponent1 INTEGER, -- d mod (p-1)
- * exponent2 INTEGER, -- d mod (q-1)
- * coefficient INTEGER, -- (inverse of q) mod p
- * otherPrimeInfos OtherPrimeInfos OPTIONAL
- * }
- */
- static public byte[] Encode (RSA rsa)
- {
- RSAParameters param = rsa.ExportParameters (true);
-
- ASN1 rsaPrivateKey = new ASN1 (0x30);
- rsaPrivateKey.Add (new ASN1 (0x02, new byte [1] { 0x00 }));
- rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.Modulus));
- rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.Exponent));
- rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.D));
- rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.P));
- rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.Q));
- rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.DP));
- rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.DQ));
- rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.InverseQ));
-
- return rsaPrivateKey.GetBytes ();
- }
-
- // DSA only encode it's X private key inside an ASN.1 INTEGER (Hint: Tag == 0x02)
- // which isn't enough for rebuilding the keypair. The other parameters
- // can be found (98% of the time) in the X.509 certificate associated
- // with the private key or (2% of the time) the parameters are in it's
- // issuer X.509 certificate (not supported in the .NET framework).
- static public DSA DecodeDSA (byte[] privateKey, DSAParameters dsaParameters)
- {
- ASN1 pvk = new ASN1 (privateKey);
- if (pvk.Tag != 0x02)
- throw new CryptographicException ("invalid private key format");
-
- // X is ALWAYS 20 bytes (no matter if the key length is 512 or 1024 bits)
- dsaParameters.X = Normalize (pvk.Value, 20);
- DSA dsa = DSA.Create ();
- dsa.ImportParameters (dsaParameters);
- return dsa;
- }
-
- static public byte[] Encode (DSA dsa)
- {
- DSAParameters param = dsa.ExportParameters (true);
- return ASN1Convert.FromUnsignedBigInteger (param.X).GetBytes ();
- }
-
- static public byte[] Encode (AsymmetricAlgorithm aa)
- {
- if (aa is RSA)
- return Encode ((RSA)aa);
- else if (aa is DSA)
- return Encode ((DSA)aa);
- else
- throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ());
- }
- }
-
- /*
- * EncryptedPrivateKeyInfo ::= SEQUENCE {
- * encryptionAlgorithm EncryptionAlgorithmIdentifier,
- * encryptedData EncryptedData
- * }
- *
- * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
- *
- * EncryptedData ::= OCTET STRING
- *
- * --
- * AlgorithmIdentifier ::= SEQUENCE {
- * algorithm OBJECT IDENTIFIER,
- * parameters ANY DEFINED BY algorithm OPTIONAL
- * }
- *
- * -- from PKCS#5
- * PBEParameter ::= SEQUENCE {
- * salt OCTET STRING SIZE(8),
- * iterationCount INTEGER
- * }
- */
- public class EncryptedPrivateKeyInfo {
-
- private string _algorithm;
- private byte[] _salt;
- private int _iterations;
- private byte[] _data;
-
- public EncryptedPrivateKeyInfo () {}
-
- public EncryptedPrivateKeyInfo (byte[] data) : this ()
- {
- Decode (data);
- }
-
- // properties
-
- public string Algorithm {
- get { return _algorithm; }
- set { _algorithm = value; }
- }
-
- public byte[] EncryptedData {
- get { return (_data == null) ? null : (byte[]) _data.Clone (); }
- set { _data = (value == null) ? null : (byte[]) value.Clone (); }
- }
-
- public byte[] Salt {
- get {
- if (_salt == null) {
- RandomNumberGenerator rng = RandomNumberGenerator.Create ();
- _salt = new byte [8];
- rng.GetBytes (_salt);
- }
- return (byte[]) _salt.Clone ();
- }
- set { _salt = (byte[]) value.Clone (); }
- }
-
- public int IterationCount {
- get { return _iterations; }
- set {
- if (value < 0)
- throw new ArgumentOutOfRangeException ("IterationCount", "Negative");
- _iterations = value;
- }
- }
-
- // methods
-
- private void Decode (byte[] data)
- {
- ASN1 encryptedPrivateKeyInfo = new ASN1 (data);
- if (encryptedPrivateKeyInfo.Tag != 0x30)
- throw new CryptographicException ("invalid EncryptedPrivateKeyInfo");
-
- ASN1 encryptionAlgorithm = encryptedPrivateKeyInfo [0];
- if (encryptionAlgorithm.Tag != 0x30)
- throw new CryptographicException ("invalid encryptionAlgorithm");
- ASN1 algorithm = encryptionAlgorithm [0];
- if (algorithm.Tag != 0x06)
- throw new CryptographicException ("invalid algorithm");
- _algorithm = ASN1Convert.ToOid (algorithm);
- // parameters ANY DEFINED BY algorithm OPTIONAL
- if (encryptionAlgorithm.Count > 1) {
- ASN1 parameters = encryptionAlgorithm [1];
- if (parameters.Tag != 0x30)
- throw new CryptographicException ("invalid parameters");
-
- ASN1 salt = parameters [0];
- if (salt.Tag != 0x04)
- throw new CryptographicException ("invalid salt");
- _salt = salt.Value;
-
- ASN1 iterationCount = parameters [1];
- if (iterationCount.Tag != 0x02)
- throw new CryptographicException ("invalid iterationCount");
- _iterations = ASN1Convert.ToInt32 (iterationCount);
- }
-
- ASN1 encryptedData = encryptedPrivateKeyInfo [1];
- if (encryptedData.Tag != 0x04)
- throw new CryptographicException ("invalid EncryptedData");
- _data = encryptedData.Value;
- }
-
- // Note: PKCS#8 doesn't define how to generate the key required for encryption
- // so you're on your own. Just don't try to copy the big guys too much ;)
- // Netscape: http://www.cs.auckland.ac.nz/~pgut001/pubs/netscape.txt
- // Microsoft: http://www.cs.auckland.ac.nz/~pgut001/pubs/breakms.txt
- public byte[] GetBytes ()
- {
- if (_algorithm == null)
- throw new CryptographicException ("No algorithm OID specified");
-
- ASN1 encryptionAlgorithm = new ASN1 (0x30);
- encryptionAlgorithm.Add (ASN1Convert.FromOid (_algorithm));
-
- // parameters ANY DEFINED BY algorithm OPTIONAL
- if ((_iterations > 0) || (_salt != null)) {
- ASN1 salt = new ASN1 (0x04, _salt);
- ASN1 iterations = ASN1Convert.FromInt32 (_iterations);
-
- ASN1 parameters = new ASN1 (0x30);
- parameters.Add (salt);
- parameters.Add (iterations);
- encryptionAlgorithm.Add (parameters);
- }
-
- // encapsulates EncryptedData into an OCTET STRING
- ASN1 encryptedData = new ASN1 (0x04, _data);
-
- ASN1 encryptedPrivateKeyInfo = new ASN1 (0x30);
- encryptedPrivateKeyInfo.Add (encryptionAlgorithm);
- encryptedPrivateKeyInfo.Add (encryptedData);
-
- return encryptedPrivateKeyInfo.GetBytes ();
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/PfxGenerator.cs b/Emby.Server.Implementations/Cryptography/PfxGenerator.cs
deleted file mode 100644
index 2d1dd649e..000000000
--- a/Emby.Server.Implementations/Cryptography/PfxGenerator.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using System;
-using System.Collections;
-using System.Security.Cryptography;
-
-namespace Emby.Server.Core.Cryptography
-{
- public class PFXGenerator
- {
- // http://www.freekpaans.nl/2015/04/creating-self-signed-x-509-certificates-using-mono-security/
- public static byte[] GeneratePfx(string certificateName, string password)
- {
- byte[] sn = GenerateSerialNumber();
- string subject = string.Format("CN={0}", certificateName);
-
- DateTime notBefore = DateTime.Now;
- DateTime notAfter = DateTime.Now.AddYears(20);
-
- RSA subjectKey = new RSACryptoServiceProvider(2048);
-
-
- string hashName = "SHA256";
-
- X509CertificateBuilder cb = new X509CertificateBuilder(3);
- cb.SerialNumber = sn;
- cb.IssuerName = subject;
- cb.NotBefore = notBefore;
- cb.NotAfter = notAfter;
- cb.SubjectName = subject;
- cb.SubjectPublicKey = subjectKey;
- cb.Hash = hashName;
-
- byte[] rawcert = cb.Sign(subjectKey);
-
-
- PKCS12 p12 = new PKCS12();
- p12.Password = password;
-
- Hashtable attributes = GetAttributes();
-
- p12.AddCertificate(new X509Certificate(rawcert), attributes);
- p12.AddPkcs8ShroudedKeyBag(subjectKey, attributes);
-
- return p12.GetBytes();
- }
-
- private static Hashtable GetAttributes()
- {
- ArrayList list = new ArrayList();
- // we use a fixed array to avoid endianess issues
- // (in case some tools requires the ID to be 1).
- list.Add(new byte[4] { 1, 0, 0, 0 });
- Hashtable attributes = new Hashtable(1);
- attributes.Add(PKCS9.localKeyId, list);
- return attributes;
- }
-
- private static byte[] GenerateSerialNumber()
- {
- byte[] sn = Guid.NewGuid().ToByteArray();
-
- //must be positive
- if ((sn[0] & 0x80) == 0x80)
- sn[0] -= 0x80;
- return sn;
- }
-
- public static byte[] GetCertificateForBytes(byte[] pfx, string password)
- {
- var pkcs = new PKCS12(pfx, password);
- var cert = pkcs.GetCertificate(GetAttributes());
-
- return cert.RawData;
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/X501Name.cs b/Emby.Server.Implementations/Cryptography/X501Name.cs
deleted file mode 100644
index 3318f95e2..000000000
--- a/Emby.Server.Implementations/Cryptography/X501Name.cs
+++ /dev/null
@@ -1,393 +0,0 @@
-//
-// X501Name.cs: X.501 Distinguished Names stuff
-//
-// Author:
-// Sebastien Pouliot <sebastien@ximian.com>
-//
-// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Globalization;
-using System.Text;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- // References:
- // 1. Information technology - Open Systems Interconnection - The Directory: Models
- // http://www.itu.int/rec/recommendation.asp?type=items&lang=e&parent=T-REC-X.501-200102-I
- // 2. RFC2253: Lightweight Directory Access Protocol (v3): UTF-8 String Representation of Distinguished Names
- // http://www.ietf.org/rfc/rfc2253.txt
-
- /*
- * Name ::= CHOICE { RDNSequence }
- *
- * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
- *
- * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
- */
- public sealed class X501 {
-
- static byte[] countryName = { 0x55, 0x04, 0x06 };
- static byte[] organizationName = { 0x55, 0x04, 0x0A };
- static byte[] organizationalUnitName = { 0x55, 0x04, 0x0B };
- static byte[] commonName = { 0x55, 0x04, 0x03 };
- static byte[] localityName = { 0x55, 0x04, 0x07 };
- static byte[] stateOrProvinceName = { 0x55, 0x04, 0x08 };
- static byte[] streetAddress = { 0x55, 0x04, 0x09 };
- //static byte[] serialNumber = { 0x55, 0x04, 0x05 };
- static byte[] domainComponent = { 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19 };
- static byte[] userid = { 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x01 };
- static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
- static byte[] dnQualifier = { 0x55, 0x04, 0x2E };
- static byte[] title = { 0x55, 0x04, 0x0C };
- static byte[] surname = { 0x55, 0x04, 0x04 };
- static byte[] givenName = { 0x55, 0x04, 0x2A };
- static byte[] initial = { 0x55, 0x04, 0x2B };
-
- private X501 ()
- {
- }
-
- static public string ToString (ASN1 seq)
- {
- StringBuilder sb = new StringBuilder ();
- for (int i = 0; i < seq.Count; i++) {
- ASN1 entry = seq [i];
- AppendEntry (sb, entry, true);
-
- // separator (not on last iteration)
- if (i < seq.Count - 1)
- sb.Append (", ");
- }
- return sb.ToString ();
- }
-
- static public string ToString (ASN1 seq, bool reversed, string separator, bool quotes)
- {
- StringBuilder sb = new StringBuilder ();
-
- if (reversed) {
- for (int i = seq.Count - 1; i >= 0; i--) {
- ASN1 entry = seq [i];
- AppendEntry (sb, entry, quotes);
-
- // separator (not on last iteration)
- if (i > 0)
- sb.Append (separator);
- }
- } else {
- for (int i = 0; i < seq.Count; i++) {
- ASN1 entry = seq [i];
- AppendEntry (sb, entry, quotes);
-
- // separator (not on last iteration)
- if (i < seq.Count - 1)
- sb.Append (separator);
- }
- }
- return sb.ToString ();
- }
-
- static private void AppendEntry (StringBuilder sb, ASN1 entry, bool quotes)
- {
- // multiple entries are valid
- for (int k = 0; k < entry.Count; k++) {
- ASN1 pair = entry [k];
- ASN1 s = pair [1];
- if (s == null)
- continue;
-
- ASN1 poid = pair [0];
- if (poid == null)
- continue;
-
- if (poid.CompareValue (countryName))
- sb.Append ("C=");
- else if (poid.CompareValue (organizationName))
- sb.Append ("O=");
- else if (poid.CompareValue (organizationalUnitName))
- sb.Append ("OU=");
- else if (poid.CompareValue (commonName))
- sb.Append ("CN=");
- else if (poid.CompareValue (localityName))
- sb.Append ("L=");
- else if (poid.CompareValue (stateOrProvinceName))
- sb.Append ("S="); // NOTE: RFC2253 uses ST=
- else if (poid.CompareValue (streetAddress))
- sb.Append ("STREET=");
- else if (poid.CompareValue (domainComponent))
- sb.Append ("DC=");
- else if (poid.CompareValue (userid))
- sb.Append ("UID=");
- else if (poid.CompareValue (email))
- sb.Append ("E="); // NOTE: Not part of RFC2253
- else if (poid.CompareValue (dnQualifier))
- sb.Append ("dnQualifier=");
- else if (poid.CompareValue (title))
- sb.Append ("T=");
- else if (poid.CompareValue (surname))
- sb.Append ("SN=");
- else if (poid.CompareValue (givenName))
- sb.Append ("G=");
- else if (poid.CompareValue (initial))
- sb.Append ("I=");
- else {
- // unknown OID
- sb.Append ("OID."); // NOTE: Not present as RFC2253
- sb.Append (ASN1Convert.ToOid (poid));
- sb.Append ("=");
- }
-
- string sValue = null;
- // 16bits or 8bits string ? TODO not complete (+special chars!)
- if (s.Tag == 0x1E) {
- // BMPSTRING
- StringBuilder sb2 = new StringBuilder ();
- for (int j = 1; j < s.Value.Length; j += 2)
- sb2.Append ((char)s.Value[j]);
- sValue = sb2.ToString ();
- } else {
- if (s.Tag == 0x14)
- sValue = Encoding.UTF7.GetString (s.Value);
- else
- sValue = Encoding.UTF8.GetString (s.Value);
- // in some cases we must quote (") the value
- // Note: this doesn't seems to conform to RFC2253
- char[] specials = { ',', '+', '"', '\\', '<', '>', ';' };
- if (quotes) {
- if ((sValue.IndexOfAny (specials, 0, sValue.Length) > 0) ||
- sValue.StartsWith (" ") || (sValue.EndsWith (" ")))
- sValue = "\"" + sValue + "\"";
- }
- }
-
- sb.Append (sValue);
-
- // separator (not on last iteration)
- if (k < entry.Count - 1)
- sb.Append (", ");
- }
- }
-
- static private X520.AttributeTypeAndValue GetAttributeFromOid (string attributeType)
- {
- string s = attributeType.ToUpper (CultureInfo.InvariantCulture).Trim ();
- switch (s) {
- case "C":
- return new X520.CountryName ();
- case "O":
- return new X520.OrganizationName ();
- case "OU":
- return new X520.OrganizationalUnitName ();
- case "CN":
- return new X520.CommonName ();
- case "L":
- return new X520.LocalityName ();
- case "S": // Microsoft
- case "ST": // RFC2253
- return new X520.StateOrProvinceName ();
- case "E": // NOTE: Not part of RFC2253
- return new X520.EmailAddress ();
- case "DC": // RFC2247
- return new X520.DomainComponent ();
- case "UID": // RFC1274
- return new X520.UserId ();
- case "DNQUALIFIER":
- return new X520.DnQualifier ();
- case "T":
- return new X520.Title ();
- case "SN":
- return new X520.Surname ();
- case "G":
- return new X520.GivenName ();
- case "I":
- return new X520.Initial ();
- default:
- if (s.StartsWith ("OID.")) {
- // MUST support it but it OID may be without it
- return new X520.Oid (s.Substring (4));
- } else {
- if (IsOid (s))
- return new X520.Oid (s);
- else
- return null;
- }
- }
- }
-
- static private bool IsOid (string oid)
- {
- try {
- ASN1 asn = ASN1Convert.FromOid (oid);
- return (asn.Tag == 0x06);
- }
- catch {
- return false;
- }
- }
-
- // no quote processing
- static private X520.AttributeTypeAndValue ReadAttribute (string value, ref int pos)
- {
- while ((value[pos] == ' ') && (pos < value.Length))
- pos++;
-
- // get '=' position in substring
- int equal = value.IndexOf ('=', pos);
- if (equal == -1) {
- string msg = ("No attribute found.");
- throw new FormatException (msg);
- }
-
- string s = value.Substring (pos, equal - pos);
- X520.AttributeTypeAndValue atv = GetAttributeFromOid (s);
- if (atv == null) {
- string msg = ("Unknown attribute '{0}'.");
- throw new FormatException (String.Format (msg, s));
- }
- pos = equal + 1; // skip the '='
- return atv;
- }
-
- static private bool IsHex (char c)
- {
- if (Char.IsDigit (c))
- return true;
- char up = Char.ToUpper (c, CultureInfo.InvariantCulture);
- return ((up >= 'A') && (up <= 'F'));
- }
-
- static string ReadHex (string value, ref int pos)
- {
- StringBuilder sb = new StringBuilder ();
- // it is (at least an) 8 bits char
- sb.Append (value[pos++]);
- sb.Append (value[pos]);
- // look ahead for a 16 bits char
- if ((pos < value.Length - 4) && (value[pos+1] == '\\') && IsHex (value[pos+2])) {
- pos += 2; // pass last char and skip \
- sb.Append (value[pos++]);
- sb.Append (value[pos]);
- }
- byte[] data = CryptoConvert.FromHex (sb.ToString ());
- return Encoding.UTF8.GetString (data);
- }
-
- static private int ReadEscaped (StringBuilder sb, string value, int pos)
- {
- switch (value[pos]) {
- case '\\':
- case '"':
- case '=':
- case ';':
- case '<':
- case '>':
- case '+':
- case '#':
- case ',':
- sb.Append (value[pos]);
- return pos;
- default:
- if (pos >= value.Length - 2) {
- string msg = ("Malformed escaped value '{0}'.");
- throw new FormatException (string.Format (msg, value.Substring (pos)));
- }
- // it's either a 8 bits or 16 bits char
- sb.Append (ReadHex (value, ref pos));
- return pos;
- }
- }
-
- static private int ReadQuoted (StringBuilder sb, string value, int pos)
- {
- int original = pos;
- while (pos <= value.Length) {
- switch (value[pos]) {
- case '"':
- return pos;
- case '\\':
- return ReadEscaped (sb, value, pos);
- default:
- sb.Append (value[pos]);
- pos++;
- break;
- }
- }
- string msg = ("Malformed quoted value '{0}'.");
- throw new FormatException (string.Format (msg, value.Substring (original)));
- }
-
- static private string ReadValue (string value, ref int pos)
- {
- int original = pos;
- StringBuilder sb = new StringBuilder ();
- while (pos < value.Length) {
- switch (value [pos]) {
- case '\\':
- pos = ReadEscaped (sb, value, ++pos);
- break;
- case '"':
- pos = ReadQuoted (sb, value, ++pos);
- break;
- case '=':
- case ';':
- case '<':
- case '>':
- string msg =("Malformed value '{0}' contains '{1}' outside quotes.");
- throw new FormatException (string.Format (msg, value.Substring (original), value[pos]));
- case '+':
- case '#':
- throw new NotImplementedException ();
- case ',':
- pos++;
- return sb.ToString ();
- default:
- sb.Append (value[pos]);
- break;
- }
- pos++;
- }
- return sb.ToString ();
- }
-
- static public ASN1 FromString (string rdn)
- {
- if (rdn == null)
- throw new ArgumentNullException ("rdn");
-
- int pos = 0;
- ASN1 asn1 = new ASN1 (0x30);
- while (pos < rdn.Length) {
- X520.AttributeTypeAndValue atv = ReadAttribute (rdn, ref pos);
- atv.Value = ReadValue (rdn, ref pos);
-
- ASN1 sequence = new ASN1 (0x31);
- sequence.Add (atv.GetASN1 ());
- asn1.Add (sequence);
- }
- return asn1;
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/X509Builder.cs b/Emby.Server.Implementations/Cryptography/X509Builder.cs
deleted file mode 100644
index a2e292350..000000000
--- a/Emby.Server.Implementations/Cryptography/X509Builder.cs
+++ /dev/null
@@ -1,153 +0,0 @@
-//
-// X509Builder.cs: Abstract builder class for X509 objects
-//
-// Author:
-// Sebastien Pouliot <sebastien@ximian.com>
-//
-// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// (C) 2004 Novell (http://www.novell.com)
-//
-
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Globalization;
-using System.Security.Cryptography;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- public abstract class X509Builder {
-
- private const string defaultHash = "SHA1";
- private string hashName;
-
- protected X509Builder ()
- {
- hashName = defaultHash;
- }
-
- protected abstract ASN1 ToBeSigned (string hashName);
-
- // move to PKCS1
- protected string GetOid (string hashName)
- {
- switch (hashName.ToLower (CultureInfo.InvariantCulture)) {
- case "md2":
- // md2withRSAEncryption (1 2 840 113549 1 1 2)
- return "1.2.840.113549.1.1.2";
- case "md4":
- // md4withRSAEncryption (1 2 840 113549 1 1 3)
- return "1.2.840.113549.1.1.3";
- case "md5":
- // md5withRSAEncryption (1 2 840 113549 1 1 4)
- return "1.2.840.113549.1.1.4";
- case "sha1":
- // sha1withRSAEncryption (1 2 840 113549 1 1 5)
- return "1.2.840.113549.1.1.5";
- case "sha256":
- // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
- return "1.2.840.113549.1.1.11";
- case "sha384":
- // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
- return "1.2.840.113549.1.1.12";
- case "sha512":
- // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
- return "1.2.840.113549.1.1.13";
- default:
- throw new NotSupportedException ("Unknown hash algorithm " + hashName);
- }
- }
-
- public string Hash {
- get { return hashName; }
- set {
- if (hashName == null)
- hashName = defaultHash;
- else
- hashName = value;
- }
- }
-
- public virtual byte[] Sign (AsymmetricAlgorithm aa)
- {
- if (aa is RSA)
- return Sign (aa as RSA);
- else if (aa is DSA)
- return Sign (aa as DSA);
- else
- throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString());
- }
-
- private byte[] Build (ASN1 tbs, string hashoid, byte[] signature)
- {
- ASN1 builder = new ASN1 (0x30);
- builder.Add (tbs);
- builder.Add (PKCS7.AlgorithmIdentifier (hashoid));
- // first byte of BITSTRING is the number of unused bits in the first byte
- byte[] bitstring = new byte [signature.Length + 1];
- Buffer.BlockCopy (signature, 0, bitstring, 1, signature.Length);
- builder.Add (new ASN1 (0x03, bitstring));
- return builder.GetBytes ();
- }
-
- public virtual byte[] Sign (RSA key)
- {
- string oid = GetOid (hashName);
- ASN1 tbs = ToBeSigned (oid);
- HashAlgorithm ha = HashAlgorithm.Create (hashName);
- byte[] hash = ha.ComputeHash (tbs.GetBytes ());
-
- RSAPKCS1SignatureFormatter pkcs1 = new RSAPKCS1SignatureFormatter (key);
- pkcs1.SetHashAlgorithm (hashName);
- byte[] signature = pkcs1.CreateSignature (hash);
-
- return Build (tbs, oid, signature);
- }
-
- public virtual byte[] Sign (DSA key)
- {
- string oid = "1.2.840.10040.4.3";
- ASN1 tbs = ToBeSigned (oid);
- HashAlgorithm ha = HashAlgorithm.Create (hashName);
- if (!(ha is SHA1))
- throw new NotSupportedException ("Only SHA-1 is supported for DSA");
- byte[] hash = ha.ComputeHash (tbs.GetBytes ());
-
- DSASignatureFormatter dsa = new DSASignatureFormatter (key);
- dsa.SetHashAlgorithm (hashName);
- byte[] rs = dsa.CreateSignature (hash);
-
- // split R and S
- byte[] r = new byte [20];
- Buffer.BlockCopy (rs, 0, r, 0, 20);
- byte[] s = new byte [20];
- Buffer.BlockCopy (rs, 20, s, 0, 20);
- ASN1 signature = new ASN1 (0x30);
- signature.Add (new ASN1 (0x02, r));
- signature.Add (new ASN1 (0x02, s));
-
- // dsaWithSha1 (1 2 840 10040 4 3)
- return Build (tbs, oid, signature.GetBytes ());
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/X509Certificate.cs b/Emby.Server.Implementations/Cryptography/X509Certificate.cs
deleted file mode 100644
index 3de58cfee..000000000
--- a/Emby.Server.Implementations/Cryptography/X509Certificate.cs
+++ /dev/null
@@ -1,563 +0,0 @@
-//
-// X509Certificates.cs: Handles X.509 certificates.
-//
-// Author:
-// Sebastien Pouliot <sebastien@xamarin.com>
-//
-// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
-// Copyright 2013 Xamarin Inc. (http://www.xamarin.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Runtime.Serialization;
-using System.Security.Cryptography;
-using System.Security.Permissions;
-using System.Text;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- // References:
- // a. Internet X.509 Public Key Infrastructure Certificate and CRL Profile
- // http://www.ietf.org/rfc/rfc3280.txt
- // b. ITU ASN.1 standards (free download)
- // http://www.itu.int/ITU-T/studygroups/com17/languages/
-
- public class X509Certificate : ISerializable
- {
-
- private ASN1 decoder;
-
- private byte[] m_encodedcert;
- private DateTime m_from;
- private DateTime m_until;
- private ASN1 issuer;
- private string m_issuername;
- private string m_keyalgo;
- private byte[] m_keyalgoparams;
- private ASN1 subject;
- private string m_subject;
- private byte[] m_publickey;
- private byte[] signature;
- private string m_signaturealgo;
- private byte[] m_signaturealgoparams;
- private byte[] certhash;
- private RSA _rsa;
- private DSA _dsa;
-
- // from http://msdn.microsoft.com/en-gb/library/ff635835.aspx
- private const string OID_DSA = "1.2.840.10040.4.1";
- private const string OID_RSA = "1.2.840.113549.1.1.1";
-
- // from http://www.ietf.org/rfc/rfc2459.txt
- //
- //Certificate ::= SEQUENCE {
- // tbsCertificate TBSCertificate,
- // signatureAlgorithm AlgorithmIdentifier,
- // signature BIT STRING }
- //
- //TBSCertificate ::= SEQUENCE {
- // version [0] Version DEFAULT v1,
- // serialNumber CertificateSerialNumber,
- // signature AlgorithmIdentifier,
- // issuer Name,
- // validity Validity,
- // subject Name,
- // subjectPublicKeyInfo SubjectPublicKeyInfo,
- // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
- // -- If present, version shall be v2 or v3
- // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
- // -- If present, version shall be v2 or v3
- // extensions [3] Extensions OPTIONAL
- // -- If present, version shall be v3 -- }
- private int version;
- private byte[] serialnumber;
-
- private byte[] issuerUniqueID;
- private byte[] subjectUniqueID;
- private X509ExtensionCollection extensions;
-
- private static string encoding_error = ("Input data cannot be coded as a valid certificate.");
-
-
- // that's were the real job is!
- private void Parse (byte[] data)
- {
- try {
- decoder = new ASN1 (data);
- // Certificate
- if (decoder.Tag != 0x30)
- throw new CryptographicException (encoding_error);
- // Certificate / TBSCertificate
- if (decoder [0].Tag != 0x30)
- throw new CryptographicException (encoding_error);
-
- ASN1 tbsCertificate = decoder [0];
-
- int tbs = 0;
- // Certificate / TBSCertificate / Version
- ASN1 v = decoder [0][tbs];
- version = 1; // DEFAULT v1
- if ((v.Tag == 0xA0) && (v.Count > 0)) {
- // version (optional) is present only in v2+ certs
- version += v [0].Value [0]; // zero based
- tbs++;
- }
-
- // Certificate / TBSCertificate / CertificateSerialNumber
- ASN1 sn = decoder [0][tbs++];
- if (sn.Tag != 0x02)
- throw new CryptographicException (encoding_error);
- serialnumber = sn.Value;
- Array.Reverse (serialnumber, 0, serialnumber.Length);
-
- // Certificate / TBSCertificate / AlgorithmIdentifier
- tbs++;
- // ASN1 signatureAlgo = tbsCertificate.Element (tbs++, 0x30);
-
- issuer = tbsCertificate.Element (tbs++, 0x30);
- m_issuername = X501.ToString (issuer);
-
- ASN1 validity = tbsCertificate.Element (tbs++, 0x30);
- ASN1 notBefore = validity [0];
- m_from = ASN1Convert.ToDateTime (notBefore);
- ASN1 notAfter = validity [1];
- m_until = ASN1Convert.ToDateTime (notAfter);
-
- subject = tbsCertificate.Element (tbs++, 0x30);
- m_subject = X501.ToString (subject);
-
- ASN1 subjectPublicKeyInfo = tbsCertificate.Element (tbs++, 0x30);
-
- ASN1 algorithm = subjectPublicKeyInfo.Element (0, 0x30);
- ASN1 algo = algorithm.Element (0, 0x06);
- m_keyalgo = ASN1Convert.ToOid (algo);
- // parameters ANY DEFINED BY algorithm OPTIONAL
- // so we dont ask for a specific (Element) type and return DER
- ASN1 parameters = algorithm [1];
- m_keyalgoparams = ((algorithm.Count > 1) ? parameters.GetBytes () : null);
-
- ASN1 subjectPublicKey = subjectPublicKeyInfo.Element (1, 0x03);
- // we must drop th first byte (which is the number of unused bits
- // in the BITSTRING)
- int n = subjectPublicKey.Length - 1;
- m_publickey = new byte [n];
- Buffer.BlockCopy (subjectPublicKey.Value, 1, m_publickey, 0, n);
-
- // signature processing
- byte[] bitstring = decoder [2].Value;
- // first byte contains unused bits in first byte
- signature = new byte [bitstring.Length - 1];
- Buffer.BlockCopy (bitstring, 1, signature, 0, signature.Length);
-
- algorithm = decoder [1];
- algo = algorithm.Element (0, 0x06);
- m_signaturealgo = ASN1Convert.ToOid (algo);
- parameters = algorithm [1];
- if (parameters != null)
- m_signaturealgoparams = parameters.GetBytes ();
- else
- m_signaturealgoparams = null;
-
- // Certificate / TBSCertificate / issuerUniqueID
- ASN1 issuerUID = tbsCertificate.Element (tbs, 0x81);
- if (issuerUID != null) {
- tbs++;
- issuerUniqueID = issuerUID.Value;
- }
-
- // Certificate / TBSCertificate / subjectUniqueID
- ASN1 subjectUID = tbsCertificate.Element (tbs, 0x82);
- if (subjectUID != null) {
- tbs++;
- subjectUniqueID = subjectUID.Value;
- }
-
- // Certificate / TBSCertificate / Extensions
- ASN1 extns = tbsCertificate.Element (tbs, 0xA3);
- if ((extns != null) && (extns.Count == 1))
- extensions = new X509ExtensionCollection (extns [0]);
- else
- extensions = new X509ExtensionCollection (null);
-
- // keep a copy of the original data
- m_encodedcert = (byte[]) data.Clone ();
- }
- catch (Exception ex) {
- throw new CryptographicException (encoding_error, ex);
- }
- }
-
- // constructors
-
- public X509Certificate (byte[] data)
- {
- if (data != null) {
- // does it looks like PEM ?
- if ((data.Length > 0) && (data [0] != 0x30)) {
- try {
- data = PEM ("CERTIFICATE", data);
- }
- catch (Exception ex) {
- throw new CryptographicException (encoding_error, ex);
- }
- }
- Parse (data);
- }
- }
-
- private byte[] GetUnsignedBigInteger (byte[] integer)
- {
- if (integer [0] == 0x00) {
- // this first byte is added so we're sure it's an unsigned integer
- // however we can't feed it into RSAParameters or DSAParameters
- int length = integer.Length - 1;
- byte[] uinteger = new byte [length];
- Buffer.BlockCopy (integer, 1, uinteger, 0, length);
- return uinteger;
- }
- else
- return integer;
- }
-
- // public methods
-
- public DSA DSA {
- get {
- if (m_keyalgoparams == null)
- throw new CryptographicException ("Missing key algorithm parameters.");
-
- if (_dsa == null && m_keyalgo == OID_DSA) {
- DSAParameters dsaParams = new DSAParameters ();
- // for DSA m_publickey contains 1 ASN.1 integer - Y
- ASN1 pubkey = new ASN1 (m_publickey);
- if ((pubkey == null) || (pubkey.Tag != 0x02))
- return null;
- dsaParams.Y = GetUnsignedBigInteger (pubkey.Value);
-
- ASN1 param = new ASN1 (m_keyalgoparams);
- if ((param == null) || (param.Tag != 0x30) || (param.Count < 3))
- return null;
- if ((param [0].Tag != 0x02) || (param [1].Tag != 0x02) || (param [2].Tag != 0x02))
- return null;
- dsaParams.P = GetUnsignedBigInteger (param [0].Value);
- dsaParams.Q = GetUnsignedBigInteger (param [1].Value);
- dsaParams.G = GetUnsignedBigInteger (param [2].Value);
-
- // BUG: MS BCL 1.0 can't import a key which
- // isn't the same size as the one present in
- // the container.
- _dsa = (DSA) new DSACryptoServiceProvider (dsaParams.Y.Length << 3);
- _dsa.ImportParameters (dsaParams);
- }
- return _dsa;
- }
-
- set {
- _dsa = value;
- if (value != null)
- _rsa = null;
- }
- }
-
- public X509ExtensionCollection Extensions {
- get { return extensions; }
- }
-
- public byte[] Hash {
- get {
- if (certhash == null) {
- if ((decoder == null) || (decoder.Count < 1))
- return null;
- string algo = PKCS1.HashNameFromOid (m_signaturealgo, false);
- if (algo == null)
- return null;
- byte[] toBeSigned = decoder [0].GetBytes ();
- using (var hash = PKCS1.CreateFromName (algo))
- certhash = hash.ComputeHash (toBeSigned, 0, toBeSigned.Length);
- }
- return (byte[]) certhash.Clone ();
- }
- }
-
- public virtual string IssuerName {
- get { return m_issuername; }
- }
-
- public virtual string KeyAlgorithm {
- get { return m_keyalgo; }
- }
-
- public virtual byte[] KeyAlgorithmParameters {
- get {
- if (m_keyalgoparams == null)
- return null;
- return (byte[]) m_keyalgoparams.Clone ();
- }
- set { m_keyalgoparams = value; }
- }
-
- public virtual byte[] PublicKey {
- get {
- if (m_publickey == null)
- return null;
- return (byte[]) m_publickey.Clone ();
- }
- }
-
- public virtual RSA RSA {
- get {
- if (_rsa == null && m_keyalgo == OID_RSA) {
- RSAParameters rsaParams = new RSAParameters ();
- // for RSA m_publickey contains 2 ASN.1 integers
- // the modulus and the public exponent
- ASN1 pubkey = new ASN1 (m_publickey);
- ASN1 modulus = pubkey [0];
- if ((modulus == null) || (modulus.Tag != 0x02))
- return null;
- ASN1 exponent = pubkey [1];
- if (exponent.Tag != 0x02)
- return null;
-
- rsaParams.Modulus = GetUnsignedBigInteger (modulus.Value);
- rsaParams.Exponent = exponent.Value;
-
- // BUG: MS BCL 1.0 can't import a key which
- // isn't the same size as the one present in
- // the container.
- int keySize = (rsaParams.Modulus.Length << 3);
- _rsa = (RSA) new RSACryptoServiceProvider (keySize);
- _rsa.ImportParameters (rsaParams);
- }
- return _rsa;
- }
-
- set {
- if (value != null)
- _dsa = null;
- _rsa = value;
- }
- }
-
- public virtual byte[] RawData {
- get {
- if (m_encodedcert == null)
- return null;
- return (byte[]) m_encodedcert.Clone ();
- }
- }
-
- public virtual byte[] SerialNumber {
- get {
- if (serialnumber == null)
- return null;
- return (byte[]) serialnumber.Clone ();
- }
- }
-
- public virtual byte[] Signature {
- get {
- if (signature == null)
- return null;
-
- switch (m_signaturealgo) {
- case "1.2.840.113549.1.1.2": // MD2 with RSA encryption
- case "1.2.840.113549.1.1.3": // MD4 with RSA encryption
- case "1.2.840.113549.1.1.4": // MD5 with RSA encryption
- case "1.2.840.113549.1.1.5": // SHA-1 with RSA Encryption
- case "1.3.14.3.2.29": // SHA1 with RSA signature
- case "1.2.840.113549.1.1.11": // SHA-256 with RSA Encryption
- case "1.2.840.113549.1.1.12": // SHA-384 with RSA Encryption
- case "1.2.840.113549.1.1.13": // SHA-512 with RSA Encryption
- case "1.3.36.3.3.1.2": // RIPEMD160 with RSA Encryption
- return (byte[]) signature.Clone ();
-
- case "1.2.840.10040.4.3": // SHA-1 with DSA
- ASN1 sign = new ASN1 (signature);
- if ((sign == null) || (sign.Count != 2))
- return null;
- byte[] part1 = sign [0].Value;
- byte[] part2 = sign [1].Value;
- byte[] sig = new byte [40];
- // parts may be less than 20 bytes (i.e. first bytes were 0x00)
- // parts may be more than 20 bytes (i.e. first byte > 0x80, negative)
- int s1 = System.Math.Max (0, part1.Length - 20);
- int e1 = System.Math.Max (0, 20 - part1.Length);
- Buffer.BlockCopy (part1, s1, sig, e1, part1.Length - s1);
- int s2 = System.Math.Max (0, part2.Length - 20);
- int e2 = System.Math.Max (20, 40 - part2.Length);
- Buffer.BlockCopy (part2, s2, sig, e2, part2.Length - s2);
- return sig;
-
- default:
- throw new CryptographicException ("Unsupported hash algorithm: " + m_signaturealgo);
- }
- }
- }
-
- public virtual string SignatureAlgorithm {
- get { return m_signaturealgo; }
- }
-
- public virtual byte[] SignatureAlgorithmParameters {
- get {
- if (m_signaturealgoparams == null)
- return m_signaturealgoparams;
- return (byte[]) m_signaturealgoparams.Clone ();
- }
- }
-
- public virtual string SubjectName {
- get { return m_subject; }
- }
-
- public virtual DateTime ValidFrom {
- get { return m_from; }
- }
-
- public virtual DateTime ValidUntil {
- get { return m_until; }
- }
-
- public int Version {
- get { return version; }
- }
-
- public bool IsCurrent {
- get { return WasCurrent (DateTime.UtcNow); }
- }
-
- public bool WasCurrent (DateTime instant)
- {
- return ((instant > ValidFrom) && (instant <= ValidUntil));
- }
-
- // uncommon v2 "extension"
- public byte[] IssuerUniqueIdentifier {
- get {
- if (issuerUniqueID == null)
- return null;
- return (byte[]) issuerUniqueID.Clone ();
- }
- }
-
- // uncommon v2 "extension"
- public byte[] SubjectUniqueIdentifier {
- get {
- if (subjectUniqueID == null)
- return null;
- return (byte[]) subjectUniqueID.Clone ();
- }
- }
-
- internal bool VerifySignature (DSA dsa)
- {
- // signatureOID is check by both this.Hash and this.Signature
- DSASignatureDeformatter v = new DSASignatureDeformatter (dsa);
- // only SHA-1 is supported
- v.SetHashAlgorithm ("SHA1");
- return v.VerifySignature (this.Hash, this.Signature);
- }
-
- internal bool VerifySignature (RSA rsa)
- {
- // SHA1-1 with DSA
- if (m_signaturealgo == "1.2.840.10040.4.3")
- return false;
- RSAPKCS1SignatureDeformatter v = new RSAPKCS1SignatureDeformatter (rsa);
- v.SetHashAlgorithm (PKCS1.HashNameFromOid (m_signaturealgo));
- return v.VerifySignature (this.Hash, this.Signature);
- }
-
- public bool VerifySignature (AsymmetricAlgorithm aa)
- {
- if (aa == null)
- throw new ArgumentNullException ("aa");
-
- if (aa is RSA)
- return VerifySignature (aa as RSA);
- else if (aa is DSA)
- return VerifySignature (aa as DSA);
- else
- throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString ());
- }
-
- public bool CheckSignature (byte[] hash, string hashAlgorithm, byte[] signature)
- {
- RSACryptoServiceProvider r = (RSACryptoServiceProvider) RSA;
- return r.VerifyHash (hash, hashAlgorithm, signature);
- }
-
- public bool IsSelfSigned {
- get {
- if (m_issuername != m_subject)
- return false;
-
- try {
- if (RSA != null)
- return VerifySignature (RSA);
- else if (DSA != null)
- return VerifySignature (DSA);
- else
- return false; // e.g. a certificate with only DSA parameters
- }
- catch (CryptographicException) {
- return false;
- }
- }
- }
-
- public ASN1 GetIssuerName ()
- {
- return issuer;
- }
-
- public ASN1 GetSubjectName ()
- {
- return subject;
- }
-
- protected X509Certificate (SerializationInfo info, StreamingContext context)
- {
- Parse ((byte[]) info.GetValue ("raw", typeof (byte[])));
- }
-
- [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
- public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
- {
- info.AddValue ("raw", m_encodedcert);
- // note: we NEVER serialize the private key
- }
-
- static byte[] PEM (string type, byte[] data)
- {
- string pem = Encoding.ASCII.GetString (data);
- string header = String.Format ("-----BEGIN {0}-----", type);
- string footer = String.Format ("-----END {0}-----", type);
- int start = pem.IndexOf (header) + header.Length;
- int end = pem.IndexOf (footer, start);
- string base64 = pem.Substring (start, (end - start));
- return Convert.FromBase64String (base64);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs b/Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs
deleted file mode 100644
index cecff6578..000000000
--- a/Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs
+++ /dev/null
@@ -1,245 +0,0 @@
-//
-// X509CertificateBuilder.cs: Handles building of X.509 certificates.
-//
-// Author:
-// Sebastien Pouliot <sebastien@ximian.com>
-//
-// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// (C) 2004 Novell (http://www.novell.com)
-//
-
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Security.Cryptography;
-
-namespace Emby.Server.Core.Cryptography
-{
- // From RFC3280
- /*
- * Certificate ::= SEQUENCE {
- * tbsCertificate TBSCertificate,
- * signatureAlgorithm AlgorithmIdentifier,
- * signature BIT STRING
- * }
- * TBSCertificate ::= SEQUENCE {
- * version [0] Version DEFAULT v1,
- * serialNumber CertificateSerialNumber,
- * signature AlgorithmIdentifier,
- * issuer Name,
- * validity Validity,
- * subject Name,
- * subjectPublicKeyInfo SubjectPublicKeyInfo,
- * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
- * -- If present, version MUST be v2 or v3
- * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
- * -- If present, version MUST be v2 or v3
- * extensions [3] Extensions OPTIONAL
- * -- If present, version MUST be v3 --
- * }
- * Version ::= INTEGER { v1(0), v2(1), v3(2) }
- * CertificateSerialNumber ::= INTEGER
- * Validity ::= SEQUENCE {
- * notBefore Time,
- * notAfter Time
- * }
- * Time ::= CHOICE {
- * utcTime UTCTime,
- * generalTime GeneralizedTime
- * }
- */
- public class X509CertificateBuilder : X509Builder {
-
- private byte version;
- private byte[] sn;
- private string issuer;
- private DateTime notBefore;
- private DateTime notAfter;
- private string subject;
- private AsymmetricAlgorithm aa;
- private byte[] issuerUniqueID;
- private byte[] subjectUniqueID;
- private X509ExtensionCollection extensions;
-
- public X509CertificateBuilder () : this (3) {}
-
- public X509CertificateBuilder (byte version)
- {
- if (version > 3)
- throw new ArgumentException ("Invalid certificate version");
- this.version = version;
- extensions = new X509ExtensionCollection ();
- }
-
- public byte Version {
- get { return version; }
- set { version = value; }
- }
-
- public byte[] SerialNumber {
- get { return sn; }
- set { sn = value; }
- }
-
- public string IssuerName {
- get { return issuer; }
- set { issuer = value; }
- }
-
- public DateTime NotBefore {
- get { return notBefore; }
- set { notBefore = value; }
- }
-
- public DateTime NotAfter {
- get { return notAfter; }
- set { notAfter = value; }
- }
-
- public string SubjectName {
- get { return subject; }
- set { subject = value; }
- }
-
- public AsymmetricAlgorithm SubjectPublicKey {
- get { return aa; }
- set { aa = value; }
- }
-
- public byte[] IssuerUniqueId {
- get { return issuerUniqueID; }
- set { issuerUniqueID = value; }
- }
-
- public byte[] SubjectUniqueId {
- get { return subjectUniqueID; }
- set { subjectUniqueID = value; }
- }
-
- public X509ExtensionCollection Extensions {
- get { return extensions; }
- }
-
-
- /* SubjectPublicKeyInfo ::= SEQUENCE {
- * algorithm AlgorithmIdentifier,
- * subjectPublicKey BIT STRING }
- */
- private ASN1 SubjectPublicKeyInfo ()
- {
- ASN1 keyInfo = new ASN1 (0x30);
- if (aa is RSA) {
- keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.113549.1.1.1"));
- RSAParameters p = (aa as RSA).ExportParameters (false);
- /* RSAPublicKey ::= SEQUENCE {
- * modulus INTEGER, -- n
- * publicExponent INTEGER } -- e
- */
- ASN1 key = new ASN1 (0x30);
- key.Add (ASN1Convert.FromUnsignedBigInteger (p.Modulus));
- key.Add (ASN1Convert.FromUnsignedBigInteger (p.Exponent));
- keyInfo.Add (new ASN1 (UniqueIdentifier (key.GetBytes ())));
- }
- else if (aa is DSA) {
- DSAParameters p = (aa as DSA).ExportParameters (false);
- /* Dss-Parms ::= SEQUENCE {
- * p INTEGER,
- * q INTEGER,
- * g INTEGER }
- */
- ASN1 param = new ASN1 (0x30);
- param.Add (ASN1Convert.FromUnsignedBigInteger (p.P));
- param.Add (ASN1Convert.FromUnsignedBigInteger (p.Q));
- param.Add (ASN1Convert.FromUnsignedBigInteger (p.G));
- keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.10040.4.1", param));
- ASN1 key = keyInfo.Add (new ASN1 (0x03));
- // DSAPublicKey ::= INTEGER -- public key, y
- key.Add (ASN1Convert.FromUnsignedBigInteger (p.Y));
- }
- else
- throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString ());
- return keyInfo;
- }
-
- private byte[] UniqueIdentifier (byte[] id)
- {
- // UniqueIdentifier ::= BIT STRING
- ASN1 uid = new ASN1 (0x03);
- // first byte in a BITSTRING is the number of unused bits in the first byte
- byte[] v = new byte [id.Length + 1];
- Buffer.BlockCopy (id, 0, v, 1, id.Length);
- uid.Value = v;
- return uid.GetBytes ();
- }
-
- protected override ASN1 ToBeSigned (string oid)
- {
- // TBSCertificate
- ASN1 tbsCert = new ASN1 (0x30);
-
- if (version > 1) {
- // TBSCertificate / [0] Version DEFAULT v1,
- byte[] ver = { (byte)(version - 1) };
- ASN1 v = tbsCert.Add (new ASN1 (0xA0));
- v.Add (new ASN1 (0x02, ver));
- }
-
- // TBSCertificate / CertificateSerialNumber,
- tbsCert.Add (new ASN1 (0x02, sn));
-
- // TBSCertificate / AlgorithmIdentifier,
- tbsCert.Add (PKCS7.AlgorithmIdentifier (oid));
-
- // TBSCertificate / Name
- tbsCert.Add (X501.FromString (issuer));
-
- // TBSCertificate / Validity
- ASN1 validity = tbsCert.Add (new ASN1 (0x30));
- // TBSCertificate / Validity / Time
- validity.Add (ASN1Convert.FromDateTime (notBefore));
- // TBSCertificate / Validity / Time
- validity.Add (ASN1Convert.FromDateTime (notAfter));
-
- // TBSCertificate / Name
- tbsCert.Add (X501.FromString (subject));
-
- // TBSCertificate / SubjectPublicKeyInfo
- tbsCert.Add (SubjectPublicKeyInfo ());
-
- if (version > 1) {
- // TBSCertificate / [1] IMPLICIT UniqueIdentifier OPTIONAL
- if (issuerUniqueID != null)
- tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (issuerUniqueID)));
-
- // TBSCertificate / [2] IMPLICIT UniqueIdentifier OPTIONAL
- if (subjectUniqueID != null)
- tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (subjectUniqueID)));
-
- // TBSCertificate / [3] Extensions OPTIONAL
- if ((version > 2) && (extensions.Count > 0))
- tbsCert.Add (new ASN1 (0xA3, extensions.GetBytes ()));
- }
-
- return tbsCert;
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs b/Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs
deleted file mode 100644
index a129bfc1a..000000000
--- a/Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs
+++ /dev/null
@@ -1,201 +0,0 @@
-//
-// Based on System.Security.Cryptography.X509Certificates.X509CertificateCollection
-// in System assembly
-//
-// Authors:
-// Lawrence Pit (loz@cable.a2000.nl)
-// Sebastien Pouliot <sebastien@ximian.com>
-//
-
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Collections;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- [Serializable]
- public class X509CertificateCollection : CollectionBase, IEnumerable {
-
- public X509CertificateCollection ()
- {
- }
-
- public X509CertificateCollection (X509Certificate [] value)
- {
- AddRange (value);
- }
-
- public X509CertificateCollection (X509CertificateCollection value)
- {
- AddRange (value);
- }
-
- // Properties
-
- public X509Certificate this [int index] {
- get { return (X509Certificate) InnerList [index]; }
- set { InnerList [index] = value; }
- }
-
- // Methods
-
- public int Add (X509Certificate value)
- {
- if (value == null)
- throw new ArgumentNullException ("value");
-
- return InnerList.Add (value);
- }
-
- public void AddRange (X509Certificate [] value)
- {
- if (value == null)
- throw new ArgumentNullException ("value");
-
- for (int i = 0; i < value.Length; i++)
- InnerList.Add (value [i]);
- }
-
- public void AddRange (X509CertificateCollection value)
- {
- if (value == null)
- throw new ArgumentNullException ("value");
-
- for (int i = 0; i < value.InnerList.Count; i++)
- InnerList.Add (value [i]);
- }
-
- public bool Contains (X509Certificate value)
- {
- return (IndexOf (value) != -1);
- }
-
- public void CopyTo (X509Certificate[] array, int index)
- {
- InnerList.CopyTo (array, index);
- }
-
- public new X509CertificateEnumerator GetEnumerator ()
- {
- return new X509CertificateEnumerator (this);
- }
-
- IEnumerator IEnumerable.GetEnumerator ()
- {
- return InnerList.GetEnumerator ();
- }
-
- public override int GetHashCode ()
- {
- return InnerList.GetHashCode ();
- }
-
- public int IndexOf (X509Certificate value)
- {
- if (value == null)
- throw new ArgumentNullException ("value");
-
- byte[] hash = value.Hash;
- for (int i=0; i < InnerList.Count; i++) {
- X509Certificate x509 = (X509Certificate) InnerList [i];
- if (Compare (x509.Hash, hash))
- return i;
- }
- return -1;
- }
-
- public void Insert (int index, X509Certificate value)
- {
- InnerList.Insert (index, value);
- }
-
- public void Remove (X509Certificate value)
- {
- InnerList.Remove (value);
- }
-
- // private stuff
-
- private bool Compare (byte[] array1, byte[] array2)
- {
- if ((array1 == null) && (array2 == null))
- return true;
- if ((array1 == null) || (array2 == null))
- return false;
- if (array1.Length != array2.Length)
- return false;
- for (int i=0; i < array1.Length; i++) {
- if (array1 [i] != array2 [i])
- return false;
- }
- return true;
- }
-
- // Inner Class
-
- public class X509CertificateEnumerator : IEnumerator {
-
- private IEnumerator enumerator;
-
- // Constructors
-
- public X509CertificateEnumerator (X509CertificateCollection mappings)
- {
- enumerator = ((IEnumerable) mappings).GetEnumerator ();
- }
-
- // Properties
-
- public X509Certificate Current {
- get { return (X509Certificate) enumerator.Current; }
- }
-
- object IEnumerator.Current {
- get { return enumerator.Current; }
- }
-
- // Methods
-
- bool IEnumerator.MoveNext ()
- {
- return enumerator.MoveNext ();
- }
-
- void IEnumerator.Reset ()
- {
- enumerator.Reset ();
- }
-
- public bool MoveNext ()
- {
- return enumerator.MoveNext ();
- }
-
- public void Reset ()
- {
- enumerator.Reset ();
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/X509Extension.cs b/Emby.Server.Implementations/Cryptography/X509Extension.cs
deleted file mode 100644
index 36b17deba..000000000
--- a/Emby.Server.Implementations/Cryptography/X509Extension.cs
+++ /dev/null
@@ -1,208 +0,0 @@
-//
-// X509Extension.cs: Base class for all X.509 extensions.
-//
-// Author:
-// Sebastien Pouliot <sebastien@ximian.com>
-//
-// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Globalization;
-using System.Text;
-
-namespace Emby.Server.Core.Cryptography
-{
- /*
- * Extension ::= SEQUENCE {
- * extnID OBJECT IDENTIFIER,
- * critical BOOLEAN DEFAULT FALSE,
- * extnValue OCTET STRING
- * }
- */
- public class X509Extension {
-
- protected string extnOid;
- protected bool extnCritical;
- protected ASN1 extnValue;
-
- protected X509Extension ()
- {
- extnCritical = false;
- }
-
- public X509Extension (ASN1 asn1)
- {
- if ((asn1.Tag != 0x30) || (asn1.Count < 2))
- throw new ArgumentException (("Invalid X.509 extension."));
- if (asn1[0].Tag != 0x06)
- throw new ArgumentException (("Invalid X.509 extension."));
-
- extnOid = ASN1Convert.ToOid (asn1[0]);
- extnCritical = ((asn1[1].Tag == 0x01) && (asn1[1].Value[0] == 0xFF));
- // last element is an octet string which may need to be decoded
- extnValue = asn1 [asn1.Count - 1];
- if ((extnValue.Tag == 0x04) && (extnValue.Length > 0) && (extnValue.Count == 0)) {
- try {
- ASN1 encapsulated = new ASN1 (extnValue.Value);
- extnValue.Value = null;
- extnValue.Add (encapsulated);
- }
- catch {
- // data isn't ASN.1
- }
- }
- Decode ();
- }
-
- public X509Extension (X509Extension extension)
- {
- if (extension == null)
- throw new ArgumentNullException ("extension");
- if ((extension.Value == null) || (extension.Value.Tag != 0x04) || (extension.Value.Count != 1))
- throw new ArgumentException (("Invalid X.509 extension."));
-
- extnOid = extension.Oid;
- extnCritical = extension.Critical;
- extnValue = extension.Value;
- Decode ();
- }
-
- // encode the extension *into* an OCTET STRING
- protected virtual void Decode ()
- {
- }
-
- // decode the extension from *inside* an OCTET STRING
- protected virtual void Encode ()
- {
- }
-
- public ASN1 ASN1 {
- get {
- ASN1 extension = new ASN1 (0x30);
- extension.Add (ASN1Convert.FromOid (extnOid));
- if (extnCritical)
- extension.Add (new ASN1 (0x01, new byte [1] { 0xFF }));
- Encode ();
- extension.Add (extnValue);
- return extension;
- }
- }
-
- public string Oid {
- get { return extnOid; }
- }
-
- public bool Critical {
- get { return extnCritical; }
- set { extnCritical = value; }
- }
-
- // this gets overrided with more meaningful names
- public virtual string Name {
- get { return extnOid; }
- }
-
- public ASN1 Value {
- get {
- if (extnValue == null) {
- Encode ();
- }
- return extnValue;
- }
- }
-
- public override bool Equals (object obj)
- {
- if (obj == null)
- return false;
-
- X509Extension ex = (obj as X509Extension);
- if (ex == null)
- return false;
-
- if (extnCritical != ex.extnCritical)
- return false;
- if (extnOid != ex.extnOid)
- return false;
- if (extnValue.Length != ex.extnValue.Length)
- return false;
-
- for (int i=0; i < extnValue.Length; i++) {
- if (extnValue [i] != ex.extnValue [i])
- return false;
- }
- return true;
- }
-
- public byte[] GetBytes ()
- {
- return ASN1.GetBytes ();
- }
-
- public override int GetHashCode ()
- {
- // OID should be unique in a collection of extensions
- return extnOid.GetHashCode ();
- }
-
- private void WriteLine (StringBuilder sb, int n, int pos)
- {
- byte[] value = extnValue.Value;
- int p = pos;
- for (int j=0; j < 8; j++) {
- if (j < n) {
- sb.Append (value [p++].ToString ("X2", CultureInfo.InvariantCulture));
- sb.Append (" ");
- }
- else
- sb.Append (" ");
- }
- sb.Append (" ");
- p = pos;
- for (int j=0; j < n; j++) {
- byte b = value [p++];
- if (b < 0x20)
- sb.Append (".");
- else
- sb.Append (Convert.ToChar (b));
- }
- sb.Append (Environment.NewLine);
- }
-
- public override string ToString ()
- {
- StringBuilder sb = new StringBuilder ();
- int div = (extnValue.Length >> 3);
- int rem = (extnValue.Length - (div << 3));
- int x = 0;
- for (int i=0; i < div; i++) {
- WriteLine (sb, 8, x);
- x += 8;
- }
- WriteLine (sb, rem, x);
- return sb.ToString ();
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/X509Extensions.cs b/Emby.Server.Implementations/Cryptography/X509Extensions.cs
deleted file mode 100644
index 018a04d79..000000000
--- a/Emby.Server.Implementations/Cryptography/X509Extensions.cs
+++ /dev/null
@@ -1,195 +0,0 @@
-//
-// X509Extensions.cs: Handles X.509 extensions.
-//
-// Author:
-// Sebastien Pouliot <sebastien@ximian.com>
-//
-// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// (C) 2004 Novell (http://www.novell.com)
-//
-
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Collections;
-
-namespace Emby.Server.Core.Cryptography
-{
- /*
- * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
- *
- * Note: 1..MAX -> There shouldn't be 0 Extensions in the ASN1 structure
- */
- public sealed class X509ExtensionCollection : CollectionBase, IEnumerable {
-
- private bool readOnly;
-
- public X509ExtensionCollection () : base ()
- {
- }
-
- public X509ExtensionCollection (ASN1 asn1) : this ()
- {
- readOnly = true;
- if (asn1 == null)
- return;
- if (asn1.Tag != 0x30)
- throw new Exception ("Invalid extensions format");
- for (int i=0; i < asn1.Count; i++) {
- X509Extension extension = new X509Extension (asn1 [i]);
- InnerList.Add (extension);
- }
- }
-
- public int Add (X509Extension extension)
- {
- if (extension == null)
- throw new ArgumentNullException ("extension");
- if (readOnly)
- throw new NotSupportedException ("Extensions are read only");
-
- return InnerList.Add (extension);
- }
-
- public void AddRange (X509Extension[] extension)
- {
- if (extension == null)
- throw new ArgumentNullException ("extension");
- if (readOnly)
- throw new NotSupportedException ("Extensions are read only");
-
- for (int i = 0; i < extension.Length; i++)
- InnerList.Add (extension [i]);
- }
-
- public void AddRange (X509ExtensionCollection collection)
- {
- if (collection == null)
- throw new ArgumentNullException ("collection");
- if (readOnly)
- throw new NotSupportedException ("Extensions are read only");
-
- for (int i = 0; i < collection.InnerList.Count; i++)
- InnerList.Add (collection [i]);
- }
-
- public bool Contains (X509Extension extension)
- {
- return (IndexOf (extension) != -1);
- }
-
- public bool Contains (string oid)
- {
- return (IndexOf (oid) != -1);
- }
-
- public void CopyTo (X509Extension[] extensions, int index)
- {
- if (extensions == null)
- throw new ArgumentNullException ("extensions");
-
- InnerList.CopyTo (extensions, index);
- }
-
- public int IndexOf (X509Extension extension)
- {
- if (extension == null)
- throw new ArgumentNullException ("extension");
-
- for (int i=0; i < InnerList.Count; i++) {
- X509Extension ex = (X509Extension) InnerList [i];
- if (ex.Equals (extension))
- return i;
- }
- return -1;
- }
-
- public int IndexOf (string oid)
- {
- if (oid == null)
- throw new ArgumentNullException ("oid");
-
- for (int i=0; i < InnerList.Count; i++) {
- X509Extension ex = (X509Extension) InnerList [i];
- if (ex.Oid == oid)
- return i;
- }
- return -1;
- }
-
- public void Insert (int index, X509Extension extension)
- {
- if (extension == null)
- throw new ArgumentNullException ("extension");
-
- InnerList.Insert (index, extension);
- }
-
- public void Remove (X509Extension extension)
- {
- if (extension == null)
- throw new ArgumentNullException ("extension");
-
- InnerList.Remove (extension);
- }
-
- public void Remove (string oid)
- {
- if (oid == null)
- throw new ArgumentNullException ("oid");
-
- int index = IndexOf (oid);
- if (index != -1)
- InnerList.RemoveAt (index);
- }
-
- IEnumerator IEnumerable.GetEnumerator ()
- {
- return InnerList.GetEnumerator ();
- }
-
- public X509Extension this [int index] {
- get { return (X509Extension) InnerList [index]; }
- }
-
- public X509Extension this [string oid] {
- get {
- int index = IndexOf (oid);
- if (index == -1)
- return null;
- return (X509Extension) InnerList [index];
- }
- }
-
- public byte[] GetBytes ()
- {
- if (InnerList.Count < 1)
- return null;
- ASN1 sequence = new ASN1 (0x30);
- for (int i=0; i < InnerList.Count; i++) {
- X509Extension x = (X509Extension) InnerList [i];
- sequence.Add (x.ASN1);
- }
- return sequence.GetBytes ();
- }
- }
-}
diff --git a/Emby.Server.Implementations/Cryptography/X520Attributes.cs b/Emby.Server.Implementations/Cryptography/X520Attributes.cs
deleted file mode 100644
index da7fd2b82..000000000
--- a/Emby.Server.Implementations/Cryptography/X520Attributes.cs
+++ /dev/null
@@ -1,346 +0,0 @@
-//
-// X520.cs: X.520 related stuff (attributes, RDN)
-//
-// Author:
-// Sebastien Pouliot <sebastien@ximian.com>
-//
-// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Text;
-
-namespace Emby.Server.Core.Cryptography
-{
-
- // References:
- // 1. Information technology - Open Systems Interconnection - The Directory: Selected attribute types
- // http://www.itu.int/rec/recommendation.asp?type=folders&lang=e&parent=T-REC-X.520
- // 2. Internet X.509 Public Key Infrastructure Certificate and CRL Profile
- // http://www.ietf.org/rfc/rfc3280.txt
- // 3. A Summary of the X.500(96) User Schema for use with LDAPv3
- // http://www.faqs.org/rfcs/rfc2256.html
- // 4. RFC 2247 - Using Domains in LDAP/X.500 Distinguished Names
- // http://www.faqs.org/rfcs/rfc2247.html
-
- /*
- * AttributeTypeAndValue ::= SEQUENCE {
- * type AttributeType,
- * value AttributeValue
- * }
- *
- * AttributeType ::= OBJECT IDENTIFIER
- *
- * AttributeValue ::= ANY DEFINED BY AttributeType
- */
- public class X520 {
-
- public abstract class AttributeTypeAndValue {
- private string oid;
- private string attrValue;
- private int upperBound;
- private byte encoding;
-
- protected AttributeTypeAndValue (string oid, int upperBound)
- {
- this.oid = oid;
- this.upperBound = upperBound;
- this.encoding = 0xFF;
- }
-
- protected AttributeTypeAndValue (string oid, int upperBound, byte encoding)
- {
- this.oid = oid;
- this.upperBound = upperBound;
- this.encoding = encoding;
- }
-
- public string Value {
- get { return attrValue; }
- set {
- if ((attrValue != null) && (attrValue.Length > upperBound)) {
- string msg = ("Value length bigger than upperbound ({0}).");
- throw new FormatException (String.Format (msg, upperBound));
- }
- attrValue = value;
- }
- }
-
- public ASN1 ASN1 {
- get { return GetASN1 (); }
- }
-
- internal ASN1 GetASN1 (byte encoding)
- {
- byte encode = encoding;
- if (encode == 0xFF)
- encode = SelectBestEncoding ();
-
- ASN1 asn1 = new ASN1 (0x30);
- asn1.Add (ASN1Convert.FromOid (oid));
- switch (encode) {
- case 0x13:
- // PRINTABLESTRING
- asn1.Add (new ASN1 (0x13, Encoding.ASCII.GetBytes (attrValue)));
- break;
- case 0x16:
- // IA5STRING
- asn1.Add (new ASN1 (0x16, Encoding.ASCII.GetBytes (attrValue)));
- break;
- case 0x1E:
- // BMPSTRING
- asn1.Add (new ASN1 (0x1E, Encoding.BigEndianUnicode.GetBytes (attrValue)));
- break;
- }
- return asn1;
- }
-
- internal ASN1 GetASN1 ()
- {
- return GetASN1 (encoding);
- }
-
- public byte[] GetBytes (byte encoding)
- {
- return GetASN1 (encoding) .GetBytes ();
- }
-
- public byte[] GetBytes ()
- {
- return GetASN1 () .GetBytes ();
- }
-
- private byte SelectBestEncoding ()
- {
- foreach (char c in attrValue) {
- switch (c) {
- case '@':
- case '_':
- return 0x1E; // BMPSTRING
- default:
- if (c > 127)
- return 0x1E; // BMPSTRING
- break;
- }
- }
- return 0x13; // PRINTABLESTRING
- }
- }
-
- public class Name : AttributeTypeAndValue {
-
- public Name () : base ("2.5.4.41", 32768)
- {
- }
- }
-
- public class CommonName : AttributeTypeAndValue {
-
- public CommonName () : base ("2.5.4.3", 64)
- {
- }
- }
-
- // RFC2256, Section 5.6
- public class SerialNumber : AttributeTypeAndValue {
-
- // max length 64 bytes, Printable String only
- public SerialNumber ()
- : base ("2.5.4.5", 64, 0x13)
- {
- }
- }
-
- public class LocalityName : AttributeTypeAndValue {
-
- public LocalityName () : base ("2.5.4.7", 128)
- {
- }
- }
-
- public class StateOrProvinceName : AttributeTypeAndValue {
-
- public StateOrProvinceName () : base ("2.5.4.8", 128)
- {
- }
- }
-
- public class OrganizationName : AttributeTypeAndValue {
-
- public OrganizationName () : base ("2.5.4.10", 64)
- {
- }
- }
-
- public class OrganizationalUnitName : AttributeTypeAndValue {
-
- public OrganizationalUnitName () : base ("2.5.4.11", 64)
- {
- }
- }
-
- // NOTE: Not part of RFC2253
- public class EmailAddress : AttributeTypeAndValue {
-
- public EmailAddress () : base ("1.2.840.113549.1.9.1", 128, 0x16)
- {
- }
- }
-
- // RFC2247, Section 4
- public class DomainComponent : AttributeTypeAndValue {
-
- // no maximum length defined
- public DomainComponent ()
- : base ("0.9.2342.19200300.100.1.25", Int32.MaxValue, 0x16)
- {
- }
- }
-
- // RFC1274, Section 9.3.1
- public class UserId : AttributeTypeAndValue {
-
- public UserId ()
- : base ("0.9.2342.19200300.100.1.1", 256)
- {
- }
- }
-
- public class Oid : AttributeTypeAndValue {
-
- public Oid (string oid)
- : base (oid, Int32.MaxValue)
- {
- }
- }
-
- /* -- Naming attributes of type X520Title
- * id-at-title AttributeType ::= { id-at 12 }
- *
- * X520Title ::= CHOICE {
- * teletexString TeletexString (SIZE (1..ub-title)),
- * printableString PrintableString (SIZE (1..ub-title)),
- * universalString UniversalString (SIZE (1..ub-title)),
- * utf8String UTF8String (SIZE (1..ub-title)),
- * bmpString BMPString (SIZE (1..ub-title))
- * }
- */
- public class Title : AttributeTypeAndValue {
-
- public Title () : base ("2.5.4.12", 64)
- {
- }
- }
-
- public class CountryName : AttributeTypeAndValue {
-
- // (0x13) PRINTABLESTRING
- public CountryName () : base ("2.5.4.6", 2, 0x13)
- {
- }
- }
-
- public class DnQualifier : AttributeTypeAndValue {
-
- // (0x13) PRINTABLESTRING
- public DnQualifier () : base ("2.5.4.46", 2, 0x13)
- {
- }
- }
-
- public class Surname : AttributeTypeAndValue {
-
- public Surname () : base ("2.5.4.4", 32768)
- {
- }
- }
-
- public class GivenName : AttributeTypeAndValue {
-
- public GivenName () : base ("2.5.4.42", 16)
- {
- }
- }
-
- public class Initial : AttributeTypeAndValue {
-
- public Initial () : base ("2.5.4.43", 5)
- {
- }
- }
-
- }
-
- /* From RFC3280
- * -- specifications of Upper Bounds MUST be regarded as mandatory
- * -- from Annex B of ITU-T X.411 Reference Definition of MTS Parameter
- *
- * -- Upper Bounds
- *
- * ub-name INTEGER ::= 32768
- * ub-common-name INTEGER ::= 64
- * ub-locality-name INTEGER ::= 128
- * ub-state-name INTEGER ::= 128
- * ub-organization-name INTEGER ::= 64
- * ub-organizational-unit-name INTEGER ::= 64
- * ub-title INTEGER ::= 64
- * ub-serial-number INTEGER ::= 64
- * ub-match INTEGER ::= 128
- * ub-emailaddress-length INTEGER ::= 128
- * ub-common-name-length INTEGER ::= 64
- * ub-country-name-alpha-length INTEGER ::= 2
- * ub-country-name-numeric-length INTEGER ::= 3
- * ub-domain-defined-attributes INTEGER ::= 4
- * ub-domain-defined-attribute-type-length INTEGER ::= 8
- * ub-domain-defined-attribute-value-length INTEGER ::= 128
- * ub-domain-name-length INTEGER ::= 16
- * ub-extension-attributes INTEGER ::= 256
- * ub-e163-4-number-length INTEGER ::= 15
- * ub-e163-4-sub-address-length INTEGER ::= 40
- * ub-generation-qualifier-length INTEGER ::= 3
- * ub-given-name-length INTEGER ::= 16
- * ub-initials-length INTEGER ::= 5
- * ub-integer-options INTEGER ::= 256
- * ub-numeric-user-id-length INTEGER ::= 32
- * ub-organization-name-length INTEGER ::= 64
- * ub-organizational-unit-name-length INTEGER ::= 32
- * ub-organizational-units INTEGER ::= 4
- * ub-pds-name-length INTEGER ::= 16
- * ub-pds-parameter-length INTEGER ::= 30
- * ub-pds-physical-address-lines INTEGER ::= 6
- * ub-postal-code-length INTEGER ::= 16
- * ub-pseudonym INTEGER ::= 128
- * ub-surname-length INTEGER ::= 40
- * ub-terminal-id-length INTEGER ::= 24
- * ub-unformatted-address-length INTEGER ::= 180
- * ub-x121-address-length INTEGER ::= 16
- *
- * -- Note - upper bounds on string types, such as TeletexString, are
- * -- measured in characters. Excepting PrintableString or IA5String, a
- * -- significantly greater number of octets will be required to hold
- * -- such a value. As a minimum, 16 octets, or twice the specified
- * -- upper bound, whichever is the larger, should be allowed for
- * -- TeletexString. For UTF8String or UniversalString at least four
- * -- times the upper bound should be allowed.
- */
-}
diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
index a34c90cb4..d207c8d4f 100644
--- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
+++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
@@ -108,37 +108,49 @@ namespace Emby.Server.Implementations.Data
var db = SQLite3.Open(DbFilePath, connectionFlags, null);
- if (string.IsNullOrWhiteSpace(_defaultWal))
+ try
{
- _defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First();
+ if (string.IsNullOrWhiteSpace(_defaultWal))
+ {
+ _defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First();
- Logger.Info("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal);
- }
+ Logger.Info("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal);
+ }
- var queries = new List<string>
- {
- //"PRAGMA cache size=-10000"
- //"PRAGMA read_uncommitted = true",
- "PRAGMA synchronous=Normal"
- };
+ var queries = new List<string>
+ {
+ //"PRAGMA cache size=-10000"
+ //"PRAGMA read_uncommitted = true",
+ "PRAGMA synchronous=Normal"
+ };
- if (CacheSize.HasValue)
- {
- queries.Add("PRAGMA cache_size=" + CacheSize.Value.ToString(CultureInfo.InvariantCulture));
- }
+ if (CacheSize.HasValue)
+ {
+ queries.Add("PRAGMA cache_size=" + CacheSize.Value.ToString(CultureInfo.InvariantCulture));
+ }
- if (EnableTempStoreMemory)
- {
- queries.Add("PRAGMA temp_store = memory");
+ if (EnableTempStoreMemory)
+ {
+ queries.Add("PRAGMA temp_store = memory");
+ }
+ else
+ {
+ queries.Add("PRAGMA temp_store = file");
+ }
+
+ foreach (var query in queries)
+ {
+ db.Execute(query);
+ }
}
- else
+ catch
{
- queries.Add("PRAGMA temp_store = file");
- }
+ using (db)
+ {
- foreach (var query in queries)
- {
- db.Execute(query);
+ }
+
+ throw;
}
_connection = new ManagedConnection(db, false);
@@ -265,29 +277,34 @@ namespace Emby.Server.Implementations.Data
{
if (dispose)
{
- try
+ DisposeConnection();
+ }
+ }
+
+ private void DisposeConnection()
+ {
+ try
+ {
+ lock (_disposeLock)
{
- lock (_disposeLock)
+ using (WriteLock.Write())
{
- using (WriteLock.Write())
+ if (_connection != null)
{
- if (_connection != null)
+ using (_connection)
{
- using (_connection)
- {
-
- }
- _connection = null;
+ _connection.Close();
}
-
- CloseConnection();
+ _connection = null;
}
+
+ CloseConnection();
}
}
- catch (Exception ex)
- {
- Logger.ErrorException("Error disposing database", ex);
- }
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error disposing database", ex);
}
}
diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
index 89664d158..1901ce848 100644
--- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
@@ -19,12 +19,14 @@ namespace Emby.Server.Implementations.Data
public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository
{
private readonly IMemoryStreamFactory _memoryStreamProvider;
+ protected IFileSystem FileSystem { get; private set; }
- public SqliteDisplayPreferencesRepository(ILogger logger, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IMemoryStreamFactory memoryStreamProvider)
+ public SqliteDisplayPreferencesRepository(ILogger logger, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IMemoryStreamFactory memoryStreamProvider, IFileSystem fileSystem)
: base(logger)
{
_jsonSerializer = jsonSerializer;
_memoryStreamProvider = memoryStreamProvider;
+ FileSystem = fileSystem;
DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db");
}
@@ -45,11 +47,27 @@ namespace Emby.Server.Implementations.Data
/// </summary>
private readonly IJsonSerializer _jsonSerializer;
+ public void Initialize()
+ {
+ try
+ {
+ InitializeInternal();
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error loading database file. Will reset and retry.", ex);
+
+ FileSystem.DeleteFile(DbFilePath);
+
+ InitializeInternal();
+ }
+ }
+
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public void Initialize()
+ private void InitializeInternal()
{
using (var connection = CreateConnection())
{
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 89ffb0fce..bc4ab8315 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -120,13 +120,13 @@ namespace Emby.Server.Implementations.Data
protected override void CloseConnection()
{
- base.CloseConnection();
-
if (_shrinkMemoryTimer != null)
{
_shrinkMemoryTimer.Dispose();
_shrinkMemoryTimer = null;
}
+
+ base.CloseConnection();
}
/// <summary>
@@ -3750,7 +3750,7 @@ namespace Emby.Server.Implementations.Data
if (query.MinDateLastSaved.HasValue)
{
- whereClauses.Add("DateLastSaved>=@MinDateLastSaved");
+ whereClauses.Add("(DateLastSaved not null and DateLastSaved>=@MinDateLastSavedForUser)");
if (statement != null)
{
statement.TryBind("@MinDateLastSaved", query.MinDateLastSaved.Value);
@@ -3759,7 +3759,7 @@ namespace Emby.Server.Implementations.Data
if (query.MinDateLastSavedForUser.HasValue)
{
- whereClauses.Add("DateLastSaved>=@MinDateLastSavedForUser");
+ whereClauses.Add("(DateLastSaved not null and DateLastSaved>=@MinDateLastSavedForUser)");
if (statement != null)
{
statement.TryBind("@MinDateLastSavedForUser", query.MinDateLastSavedForUser.Value);
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index c5fcc0e4c..9f08c6462 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -571,7 +571,7 @@ namespace Emby.Server.Implementations.Dto
}
}
- if (!(item is LiveTvProgram) || fields.Contains(ItemFields.PlayAccess))
+ if (/*!(item is LiveTvProgram) ||*/ fields.Contains(ItemFields.PlayAccess))
{
dto.PlayAccess = item.GetPlayAccess(user);
}
@@ -1642,6 +1642,9 @@ namespace Emby.Server.Implementations.Dto
return null;
}
+ return null;
+ _logger.Info("Getting image size for item type {0}", item.GetType().Name);
+
try
{
size = _imageProcessor.GetImageSize(imageInfo);
@@ -1673,22 +1676,6 @@ namespace Emby.Server.Implementations.Dto
return null;
}
- var photo = item as Photo;
- if (photo != null && photo.Orientation.HasValue)
- {
- switch (photo.Orientation.Value)
- {
- case ImageOrientation.LeftBottom:
- case ImageOrientation.LeftTop:
- case ImageOrientation.RightBottom:
- case ImageOrientation.RightTop:
- var temp = height;
- height = width;
- width = temp;
- break;
- }
- }
-
return width / height;
}
}
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index ccff29eef..518fa0d38 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -56,25 +56,7 @@
<Compile Include="Collections\CollectionManager.cs" />
<Compile Include="Collections\CollectionsDynamicFolder.cs" />
<Compile Include="Configuration\ServerConfigurationManager.cs" />
- <Compile Include="Cryptography\ASN1.cs" />
- <Compile Include="Cryptography\ASN1Convert.cs" />
- <Compile Include="Cryptography\BitConverterLE.cs" />
- <Compile Include="Cryptography\CertificateGenerator.cs" />
- <Compile Include="Cryptography\CryptoConvert.cs" />
<Compile Include="Cryptography\CryptographyProvider.cs" />
- <Compile Include="Cryptography\PfxGenerator.cs" />
- <Compile Include="Cryptography\PKCS1.cs" />
- <Compile Include="Cryptography\PKCS12.cs" />
- <Compile Include="Cryptography\PKCS7.cs" />
- <Compile Include="Cryptography\PKCS8.cs" />
- <Compile Include="Cryptography\X501Name.cs" />
- <Compile Include="Cryptography\X509Builder.cs" />
- <Compile Include="Cryptography\X509Certificate.cs" />
- <Compile Include="Cryptography\X509CertificateBuilder.cs" />
- <Compile Include="Cryptography\X509CertificateCollection.cs" />
- <Compile Include="Cryptography\X509Extension.cs" />
- <Compile Include="Cryptography\X509Extensions.cs" />
- <Compile Include="Cryptography\X520Attributes.cs" />
<Compile Include="Data\ManagedConnection.cs" />
<Compile Include="Data\SqliteDisplayPreferencesRepository.cs" />
<Compile Include="Data\SqliteItemRepository.cs" />
@@ -425,10 +407,9 @@
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHost.cs" />
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHttpStream.cs" />
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunUdpStream.cs" />
+ <Compile Include="LiveTv\TunerHosts\LiveStream.cs" />
<Compile Include="LiveTv\TunerHosts\M3uParser.cs" />
<Compile Include="LiveTv\TunerHosts\M3UTunerHost.cs" />
- <Compile Include="LiveTv\TunerHosts\MulticastStream.cs" />
- <Compile Include="LiveTv\TunerHosts\QueueStream.cs" />
<Compile Include="Localization\LocalizationManager.cs" />
<Compile Include="Localization\TextLocalizer.cs" />
<Compile Include="Logging\ConsoleLogger.cs" />
@@ -667,8 +648,8 @@
<HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
<Private>True</Private>
</Reference>
- <Reference Include="SharpCompress, Version=0.14.0.0, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\SharpCompress.0.14.0\lib\net45\SharpCompress.dll</HintPath>
+ <Reference Include="SharpCompress, Version=0.18.2.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
+ <HintPath>..\packages\SharpCompress.0.18.2\lib\net45\SharpCompress.dll</HintPath>
</Reference>
<Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
index 9b434d606..2cef46839 100644
--- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
+++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
@@ -48,7 +48,7 @@ namespace Emby.Server.Implementations.EntryPoints
values.Add(config.PublicPort.ToString(CultureInfo.InvariantCulture));
values.Add(_appHost.HttpPort.ToString(CultureInfo.InvariantCulture));
values.Add(_appHost.HttpsPort.ToString(CultureInfo.InvariantCulture));
- values.Add(config.EnableHttps.ToString());
+ values.Add((config.EnableHttps || config.RequireHttps).ToString());
values.Add(_appHost.EnableHttps.ToString());
return string.Join("|", values.ToArray(values.Count));
diff --git a/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs
index fb9402986..11e806b0c 100644
--- a/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs
@@ -74,7 +74,7 @@ namespace Emby.Server.Implementations.EntryPoints
try
{
- await new UsageReporter(_applicationHost, _httpClient, _userManager, _logger)
+ await new UsageReporter(_applicationHost, _httpClient, _logger)
.ReportAppUsage(client, CancellationToken.None)
.ConfigureAwait(false);
}
@@ -117,7 +117,7 @@ namespace Emby.Server.Implementations.EntryPoints
try
{
- await new UsageReporter(_applicationHost, _httpClient, _userManager, _logger)
+ await new UsageReporter(_applicationHost, _httpClient, _logger)
.ReportServerUsage(CancellationToken.None)
.ConfigureAwait(false);
}
diff --git a/Emby.Server.Implementations/EntryPoints/UsageReporter.cs b/Emby.Server.Implementations/EntryPoints/UsageReporter.cs
index 778c8a6ce..deee8d64b 100644
--- a/Emby.Server.Implementations/EntryPoints/UsageReporter.cs
+++ b/Emby.Server.Implementations/EntryPoints/UsageReporter.cs
@@ -17,15 +17,13 @@ namespace Emby.Server.Implementations.EntryPoints
{
private readonly IServerApplicationHost _applicationHost;
private readonly IHttpClient _httpClient;
- private readonly IUserManager _userManager;
private readonly ILogger _logger;
private const string MbAdminUrl = "https://www.mb3admin.com/admin/";
- public UsageReporter(IServerApplicationHost applicationHost, IHttpClient httpClient, IUserManager userManager, ILogger logger)
+ public UsageReporter(IServerApplicationHost applicationHost, IHttpClient httpClient, ILogger logger)
{
_applicationHost = applicationHost;
_httpClient = httpClient;
- _userManager = userManager;
_logger = logger;
}
@@ -43,12 +41,6 @@ namespace Emby.Server.Implementations.EntryPoints
{ "platform", _applicationHost.OperatingSystemDisplayName }
};
- var users = _userManager.Users.ToList();
-
- data["localusers"] = users.Count(i => !i.ConnectLinkType.HasValue).ToString(CultureInfo.InvariantCulture);
- data["guests"] = users.Count(i => i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest).ToString(CultureInfo.InvariantCulture);
- data["linkedusers"] = users.Count(i => i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.LinkedUser).ToString(CultureInfo.InvariantCulture);
-
data["plugins"] = string.Join(",", _applicationHost.Plugins.Select(i => i.Id).ToArray());
var logErrors = false;
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index 86df798d0..737d4ceea 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -423,6 +424,22 @@ namespace Emby.Server.Implementations.HttpServer
return true;
}
+ private bool ValidateSsl(string remoteIp, string urlString)
+ {
+ if (_config.Configuration.RequireHttps && _appHost.EnableHttps)
+ {
+ if (urlString.IndexOf("https://", StringComparison.OrdinalIgnoreCase) == -1)
+ {
+ if (!_networkManager.IsInLocalNetwork(remoteIp))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
/// <summary>
/// Overridable method that can be used to implement a custom hnandler
/// </summary>
@@ -453,6 +470,16 @@ namespace Emby.Server.Implementations.HttpServer
return;
}
+ if (!ValidateSsl(httpReq.RemoteIp, urlString))
+ {
+ var httpsUrl = urlString
+ .Replace("http://", "https://", StringComparison.OrdinalIgnoreCase)
+ .Replace(":" + _config.Configuration.PublicPort.ToString(CultureInfo.InvariantCulture), ":" + _config.Configuration.PublicHttpsPort.ToString(CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase);
+
+ RedirectToUrl(httpRes, httpsUrl);
+ return;
+ }
+
if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
{
httpRes.StatusCode = 200;
@@ -468,7 +495,7 @@ namespace Emby.Server.Implementations.HttpServer
enableLog = EnableLogging(urlString, localPath);
urlToLog = urlString;
- logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
+ logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
if (enableLog)
{
@@ -579,7 +606,13 @@ namespace Emby.Server.Implementations.HttpServer
catch (Exception ex)
{
- ErrorHandler(ex, httpReq, !string.Equals(ex.GetType().Name, "SocketException", StringComparison.OrdinalIgnoreCase));
+ var logException = !string.Equals(ex.GetType().Name, "SocketException", StringComparison.OrdinalIgnoreCase);
+
+#if DEBUG
+ logException = true;
+#endif
+
+ ErrorHandler(ex, httpReq, logException);
}
finally
{
@@ -725,6 +758,12 @@ namespace Emby.Server.Implementations.HttpServer
public object DeserializeJson(Type type, Stream stream)
{
+ //using (var reader = new StreamReader(stream))
+ //{
+ // var json = reader.ReadToEnd();
+ // Logger.Info(json);
+ // return _jsonSerializer.DeserializeFromString(json, type);
+ //}
return _jsonSerializer.DeserializeFromStream(stream, type);
}
diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
index f30879c62..86deccee1 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -142,8 +142,6 @@ namespace Emby.Server.Implementations.HttpServer
throw new ArgumentNullException("result");
}
- var optimizedResult = ToOptimizedResult(requestContext, result);
-
if (responseHeaders == null)
{
responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
@@ -154,15 +152,7 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders["Expires"] = "-1";
}
- // Apply headers
- var hasHeaders = optimizedResult as IHasHeaders;
-
- if (hasHeaders != null)
- {
- AddResponseHeaders(hasHeaders, responseHeaders);
- }
-
- return optimizedResult;
+ return ToOptimizedResultInternal(requestContext, result, responseHeaders);
}
public static string GetCompressionType(IRequest request)
@@ -190,6 +180,11 @@ namespace Emby.Server.Implementations.HttpServer
/// <returns></returns>
public object ToOptimizedResult<T>(IRequest request, T dto)
{
+ return ToOptimizedResultInternal(request, dto, null);
+ }
+
+ private object ToOptimizedResultInternal<T>(IRequest request, T dto, IDictionary<string, string> responseHeaders = null)
+ {
var contentType = request.ResponseContentType;
switch (GetRealContentType(contentType))
@@ -197,27 +192,27 @@ namespace Emby.Server.Implementations.HttpServer
case "application/xml":
case "text/xml":
case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
- return SerializeToXmlString(dto);
+ return GetHttpResult(SerializeToXmlString(dto), contentType, false, responseHeaders);
case "application/json":
case "text/json":
- return _jsonSerializer.SerializeToString(dto);
+ return GetHttpResult(_jsonSerializer.SerializeToString(dto), contentType, false, responseHeaders);
default:
- {
- var ms = new MemoryStream();
- var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
+ {
+ var ms = new MemoryStream();
+ var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
- writerFn(dto, ms);
-
- ms.Position = 0;
+ writerFn(dto, ms);
- if (string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase))
- {
- return GetHttpResult(new byte[] { }, contentType, true);
- }
+ ms.Position = 0;
- return GetHttpResult(ms, contentType, true);
+ if (string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase))
+ {
+ return GetHttpResult(new byte[] { }, contentType, true, responseHeaders);
}
+
+ return GetHttpResult(ms, contentType, true, responseHeaders);
+ }
}
}
@@ -360,7 +355,7 @@ namespace Emby.Server.Implementations.HttpServer
if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration))
{
AddAgeHeader(responseHeaders, lastDateModified);
- AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration, noCache);
+ AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration);
var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified);
@@ -370,7 +365,7 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration, noCache);
+ AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration);
return null;
}
@@ -424,16 +419,6 @@ namespace Emby.Server.Implementations.HttpServer
options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- if (!options.ResponseHeaders.ContainsKey("Content-Disposition"))
- {
- // Quotes are valid in linux. They'll possibly cause issues here
- var filename = (Path.GetFileName(path) ?? string.Empty).Replace("\"", string.Empty);
- if (!string.IsNullOrWhiteSpace(filename))
- {
- options.ResponseHeaders["Content-Disposition"] = "inline; filename=\"" + filename + "\"";
- }
- }
-
return GetStaticResult(requestContext, options);
}
@@ -490,7 +475,8 @@ namespace Emby.Server.Implementations.HttpServer
return result;
}
- var isHeadRequest = options.IsHeadRequest;
+ // TODO: We don't really need the option value
+ var isHeadRequest = options.IsHeadRequest || string.Equals(requestContext.Verb, "HEAD", StringComparison.OrdinalIgnoreCase);
var factoryFn = options.ContentFactory;
var responseHeaders = options.ResponseHeaders;
@@ -555,7 +541,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary>
/// Adds the caching responseHeaders.
/// </summary>
- private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, bool noCache)
+ private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration)
{
// Don't specify both last modified and Etag, unless caching unconditionally. They are redundant
// https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching
@@ -565,11 +551,11 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r");
}
- if (!noCache && cacheDuration.HasValue)
+ if (cacheDuration.HasValue)
{
responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds);
}
- else if (!noCache && !string.IsNullOrEmpty(cacheKey))
+ else if (!string.IsNullOrEmpty(cacheKey))
{
responseHeaders["Cache-Control"] = "public";
}
@@ -579,15 +565,15 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders["pragma"] = "no-cache, no-store, must-revalidate";
}
- AddExpiresHeader(responseHeaders, cacheKey, cacheDuration, noCache);
+ AddExpiresHeader(responseHeaders, cacheKey, cacheDuration);
}
/// <summary>
/// Adds the expires header.
/// </summary>
- private void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration, bool noCache)
+ private void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration)
{
- if (!noCache && cacheDuration.HasValue)
+ if (cacheDuration.HasValue)
{
responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r");
}
diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs
index 56b10a7e6..c99b601c9 100644
--- a/Emby.Server.Implementations/IO/LibraryMonitor.cs
+++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs
@@ -333,13 +333,7 @@ namespace Emby.Server.Implementations.IO
NotifyFilters.Attributes;
newWatcher.Created += watcher_Changed;
-
- // Seeing mono crashes on background threads we can't catch, testing if this might help
- if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows)
- {
- newWatcher.Deleted += watcher_Changed;
- }
-
+ newWatcher.Deleted += watcher_Changed;
newWatcher.Renamed += watcher_Changed;
newWatcher.Changed += watcher_Changed;
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index eab52e5e8..85b91ac25 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -247,11 +247,6 @@ namespace Emby.Server.Implementations.Library
}
}
- /// <summary>
- /// The _season zero display name
- /// </summary>
- private string _seasonZeroDisplayName;
-
private bool _wizardCompleted;
/// <summary>
/// Records the configuration values.
@@ -259,7 +254,6 @@ namespace Emby.Server.Implementations.Library
/// <param name="configuration">The configuration.</param>
private void RecordConfigurationValues(ServerConfiguration configuration)
{
- _seasonZeroDisplayName = configuration.SeasonZeroDisplayName;
_wizardCompleted = configuration.IsStartupWizardCompleted;
}
@@ -272,59 +266,14 @@ namespace Emby.Server.Implementations.Library
{
var config = ConfigurationManager.Configuration;
- var newSeasonZeroName = ConfigurationManager.Configuration.SeasonZeroDisplayName;
- var seasonZeroNameChanged = !string.Equals(_seasonZeroDisplayName, newSeasonZeroName, StringComparison.Ordinal);
var wizardChanged = config.IsStartupWizardCompleted != _wizardCompleted;
RecordConfigurationValues(config);
- if (seasonZeroNameChanged || wizardChanged)
+ if (wizardChanged)
{
_taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
}
-
- if (seasonZeroNameChanged)
- {
- Task.Run(async () =>
- {
- await UpdateSeasonZeroNames(newSeasonZeroName, CancellationToken.None).ConfigureAwait(false);
-
- });
- }
- }
-
- /// <summary>
- /// Updates the season zero names.
- /// </summary>
- /// <param name="newName">The new name.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task UpdateSeasonZeroNames(string newName, CancellationToken cancellationToken)
- {
- var seasons = GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(Season).Name },
- Recursive = true,
- IndexNumber = 0,
- DtoOptions = new DtoOptions(true)
-
- }).Cast<Season>()
- .Where(i => !string.Equals(i.Name, newName, StringComparison.Ordinal))
- .ToList();
-
- foreach (var season in seasons)
- {
- season.Name = newName;
-
- try
- {
- await UpdateItem(season, ItemUpdateType.MetadataDownload, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving {0}", ex, season.Path);
- }
- }
}
public void RegisterItem(BaseItem item)
@@ -433,6 +382,14 @@ namespace Emby.Server.Implementations.Library
_fileSystem.DeleteFile(fileSystemInfo.FullName);
}
}
+ catch (FileNotFoundException)
+ {
+ // may have already been deleted manually by user
+ }
+ catch (DirectoryNotFoundException)
+ {
+ // may have already been deleted manually by user
+ }
catch (IOException)
{
if (isRequiredForDelete)
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
index bbe1bba85..a859d8ec8 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
@@ -55,9 +55,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
if (season.IndexNumber.HasValue)
{
var seasonNumber = season.IndexNumber.Value;
-
+
season.Name = seasonNumber == 0 ?
- _config.Configuration.SeasonZeroDisplayName :
+ args.LibraryOptions.SeasonZeroDisplayName :
string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.ToString(UsCulture));
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 1975a6b01..4a2836d59 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -1006,7 +1006,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
private readonly SemaphoreSlim _liveStreamsSemaphore = new SemaphoreSlim(1, 1);
- private readonly List<LiveStream> _liveStreams = new List<LiveStream>();
+ private readonly List<ILiveStream> _liveStreams = new List<ILiveStream>();
public async Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
{
@@ -1039,7 +1039,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return mediaSource;
}
- public async Task<LiveStream> GetLiveStream(string uniqueId)
+ public async Task<ILiveStream> GetLiveStream(string uniqueId)
{
await _liveStreamsSemaphore.WaitAsync().ConfigureAwait(false);
@@ -1055,7 +1055,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
- private async Task<Tuple<LiveStream, MediaSourceInfo, ITunerHost>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
+ private async Task<Tuple<ILiveStream, MediaSourceInfo, ITunerHost>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
{
_logger.Info("Streaming Channel " + channelId);
@@ -1072,7 +1072,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount);
- return new Tuple<LiveStream, MediaSourceInfo, ITunerHost>(result, openedMediaSource, result.TunerHost);
+ return new Tuple<ILiveStream, MediaSourceInfo, ITunerHost>(result, openedMediaSource, result.TunerHost);
}
foreach (var hostInstance in _liveTvManager.TunerHosts)
@@ -1092,7 +1092,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_logger.Info("Returning mediasource streamId {0}, mediaSource.Id {1}, mediaSource.LiveStreamId {2}",
streamId, openedMediaSource.Id, openedMediaSource.LiveStreamId);
- return new Tuple<LiveStream, MediaSourceInfo, ITunerHost>(result, openedMediaSource, hostInstance);
+ return new Tuple<ILiveStream, MediaSourceInfo, ITunerHost>(result, openedMediaSource, hostInstance);
}
catch (FileNotFoundException)
{
@@ -1718,7 +1718,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
var parent = _fileSystem.GetDirectoryName(originalPath);
var name = Path.GetFileNameWithoutExtension(originalPath);
- name += "-" + index.ToString(CultureInfo.InvariantCulture);
+ name += " - " + index.ToString(CultureInfo.InvariantCulture);
path = Path.ChangeExtension(Path.Combine(parent, name), Path.GetExtension(originalPath));
index++;
diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
index fb8308cda..8ea98879a 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
@@ -65,7 +65,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (!path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
- return path;
+ return UnzipIfNeeded(path, path);
}
var cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + ".xml";
@@ -94,46 +94,30 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFile));
- using (var stream = _fileSystem.OpenRead(tempFile))
- {
- using (var reader = new StreamReader(stream, Encoding.UTF8))
- {
- using (var fileStream = _fileSystem.GetFileStream(cacheFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
- {
- using (var writer = new StreamWriter(fileStream))
- {
- while (!reader.EndOfStream)
- {
- writer.WriteLine(reader.ReadLine());
- }
- }
- }
- }
- }
+ _fileSystem.CopyFile(tempFile, cacheFile, true);
- _logger.Debug("Returning xmltv path {0}", cacheFile);
return UnzipIfNeeded(path, cacheFile);
}
private string UnzipIfNeeded(string originalUrl, string file)
{
- //var ext = Path.GetExtension(originalUrl);
-
- //if (string.Equals(ext, ".gz", StringComparison.OrdinalIgnoreCase))
- //{
- // using (var stream = _fileSystem.OpenRead(file))
- // {
- // var tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString());
- // _fileSystem.CreateDirectory(tempFolder);
-
- // _zipClient.ExtractAllFromZip(stream, tempFolder, true);
-
- // return _fileSystem.GetFiles(tempFolder, true)
- // .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
- // .Select(i => i.FullName)
- // .FirstOrDefault();
- // }
- //}
+ var ext = Path.GetExtension(originalUrl.Split('?')[0]);
+
+ if (string.Equals(ext, ".gz", StringComparison.OrdinalIgnoreCase))
+ {
+ using (var stream = _fileSystem.OpenRead(file))
+ {
+ var tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString());
+ _fileSystem.CreateDirectory(tempFolder);
+
+ _zipClient.ExtractAllFromGz(stream, tempFolder, true);
+
+ return _fileSystem.GetFiles(tempFolder, true)
+ .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
+ .Select(i => i.FullName)
+ .FirstOrDefault();
+ }
+ }
return file;
}
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 38d2fd3c6..857afa378 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -78,7 +78,7 @@ namespace Emby.Server.Implementations.LiveTv
return EmbyTV.EmbyTV.Current.GetActiveRecordingPath(id);
}
- public Task<LiveStream> GetEmbyTvLiveStream(string id)
+ public Task<ILiveStream> GetEmbyTvLiveStream(string id)
{
return EmbyTV.EmbyTV.Current.GetLiveStream(id);
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index 4b4f61d53..e0fd32aee 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -193,9 +193,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return new List<MediaSourceInfo>();
}
- protected abstract Task<LiveStream> GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken);
+ protected abstract Task<ILiveStream> GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken);
- public async Task<LiveStream> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
+ public async Task<ILiveStream> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(channelId))
{
@@ -247,7 +247,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
try
{
var liveStream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
+ var startTime = DateTime.UtcNow;
await liveStream.Open(cancellationToken).ConfigureAwait(false);
+ var endTime = DateTime.UtcNow;
+ Logger.Info("Live stream opened after {0}ms", (endTime - startTime).TotalMilliseconds);
return liveStream;
}
catch (Exception ex)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index f974b5c2c..bb11dac5f 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -347,6 +347,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
videoCodec = "h264";
videoBitrate = 1000000;
}
+ else
+ {
+ // This is for android tv's 1200 condition. Remove once not needed anymore so that we can avoid possible side effects of dummying up this data
+ if ((channelInfo.IsHD ?? true))
+ {
+ width = 1920;
+ height = 1080;
+ }
+ }
if (channelInfo != null)
{
@@ -491,7 +500,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return list;
}
- protected override async Task<LiveStream> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
+ protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
{
var profile = streamId.Split('_')[0];
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
new file mode 100644
index 000000000..4641a1c91
--- /dev/null
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
@@ -0,0 +1,153 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.IO;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.System;
+
+namespace Emby.Server.Implementations.LiveTv.TunerHosts
+{
+ public class LiveStream : ILiveStream
+ {
+ public MediaSourceInfo OriginalMediaSource { get; set; }
+ public MediaSourceInfo OpenedMediaSource { get; set; }
+ public int ConsumerCount
+ {
+ get { return SharedStreamIds.Count; }
+ }
+ public ITunerHost TunerHost { get; set; }
+ public string OriginalStreamId { get; set; }
+ public bool EnableStreamSharing { get; set; }
+ public string UniqueId { get; private set; }
+
+ public List<string> SharedStreamIds { get; private set; }
+ protected readonly IEnvironmentInfo Environment;
+ protected readonly IFileSystem FileSystem;
+
+ protected readonly string TempFilePath;
+ protected readonly ILogger Logger;
+
+ public LiveStream(MediaSourceInfo mediaSource, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger, IServerApplicationPaths appPaths)
+ {
+ OriginalMediaSource = mediaSource;
+ Environment = environment;
+ FileSystem = fileSystem;
+ OpenedMediaSource = mediaSource;
+ Logger = logger;
+ EnableStreamSharing = true;
+ SharedStreamIds = new List<string>();
+ UniqueId = Guid.NewGuid().ToString("N");
+ TempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts");
+ }
+
+ public Task Open(CancellationToken cancellationToken)
+ {
+ return OpenInternal(cancellationToken);
+ }
+
+ protected virtual Task OpenInternal(CancellationToken cancellationToken)
+ {
+ return Task.FromResult(true);
+ }
+
+ public virtual Task Close()
+ {
+ return Task.FromResult(true);
+ }
+
+ protected Stream GetInputStream(string path, bool allowAsyncFileRead)
+ {
+ var fileOpenOptions = FileOpenOptions.SequentialScan;
+
+ if (allowAsyncFileRead)
+ {
+ fileOpenOptions |= FileOpenOptions.Asynchronous;
+ }
+
+ return FileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, fileOpenOptions);
+ }
+
+ protected async Task DeleteTempFile(string path, int retryCount = 0)
+ {
+ try
+ {
+ FileSystem.DeleteFile(path);
+ return;
+ }
+ catch
+ {
+
+ }
+
+ if (retryCount > 20)
+ {
+ return;
+ }
+
+ await Task.Delay(500).ConfigureAwait(false);
+ await DeleteTempFile(path, retryCount + 1).ConfigureAwait(false);
+ }
+
+ public async Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
+ {
+ var allowAsync = false;//Environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows;
+ // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
+
+ using (var inputStream = (FileStream)GetInputStream(TempFilePath, allowAsync))
+ {
+ TrySeek(inputStream, -20000);
+
+ await CopyTo(inputStream, stream, 81920, null, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ private static async Task CopyTo(Stream source, Stream destination, int bufferSize, Action onStarted, CancellationToken cancellationToken)
+ {
+ byte[] buffer = new byte[bufferSize];
+ while (true)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var read = source.Read(buffer, 0, buffer.Length);
+
+ if (read > 0)
+ {
+ //await destination.WriteAsync(buffer, 0, read).ConfigureAwait(false);
+ destination.Write(buffer, 0, read);
+
+ if (onStarted != null)
+ {
+ onStarted();
+ onStarted = null;
+ }
+ }
+ else
+ {
+ await Task.Delay(10).ConfigureAwait(false);
+ }
+ }
+ }
+
+ private void TrySeek(FileStream stream, long offset)
+ {
+ try
+ {
+ stream.Seek(offset, SeekOrigin.End);
+ }
+ catch (ArgumentException)
+ {
+
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error seeking stream", ex);
+ }
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index eac845579..8d1854f4b 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -75,11 +75,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return Task.FromResult(list);
}
- protected override async Task<LiveStream> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
+ protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
{
var sources = await GetChannelStreamMediaSources(info, channelId, cancellationToken).ConfigureAwait(false);
- var liveStream = new LiveStream(sources.First(), _environment, FileSystem);
+ var liveStream = new LiveStream(sources.First(), _environment, FileSystem, Logger, Config.ApplicationPaths);
return liveStream;
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
deleted file mode 100644
index 45a0c348e..000000000
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-
-namespace Emby.Server.Implementations.LiveTv.TunerHosts
-{
- public class MulticastStream
- {
- private readonly ConcurrentDictionary<Guid, QueueStream> _outputStreams = new ConcurrentDictionary<Guid, QueueStream>();
- private const int BufferSize = 81920;
- private readonly ILogger _logger;
-
- public MulticastStream(ILogger logger)
- {
- _logger = logger;
- }
-
- public async Task CopyUntilCancelled(Stream source, Action onStarted, CancellationToken cancellationToken)
- {
- if (source == null)
- {
- throw new ArgumentNullException("source");
- }
-
- while (true)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- byte[] buffer = new byte[BufferSize];
-
- var bytesRead = source.Read(buffer, 0, buffer.Length);
-
- if (bytesRead > 0)
- {
- foreach (var stream in _outputStreams)
- {
- stream.Value.Queue(buffer, 0, bytesRead);
- }
-
- if (onStarted != null)
- {
- var onStartedCopy = onStarted;
- onStarted = null;
- Task.Run(onStartedCopy);
- }
- }
-
- else
- {
- await Task.Delay(100).ConfigureAwait(false);
- }
- }
- }
-
- public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
- {
- var queueStream = new QueueStream(stream, _logger);
-
- _outputStreams.TryAdd(queueStream.Id, queueStream);
-
- try
- {
- queueStream.Start(cancellationToken);
- }
- finally
- {
- _outputStreams.TryRemove(queueStream.Id, out queueStream);
- GC.Collect();
- }
-
- return Task.FromResult(true);
- }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
deleted file mode 100644
index 07a4daa87..000000000
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-
-namespace Emby.Server.Implementations.LiveTv.TunerHosts
-{
- public class QueueStream
- {
- private readonly Stream _outputStream;
- private readonly BlockingCollection<Tuple<byte[], int, int>> _queue = new BlockingCollection<Tuple<byte[], int, int>>();
-
- private readonly ILogger _logger;
- public Guid Id = Guid.NewGuid();
-
- public QueueStream(Stream outputStream, ILogger logger)
- {
- _outputStream = outputStream;
- _logger = logger;
- }
-
- public void Queue(byte[] bytes, int offset, int count)
- {
- _queue.Add(new Tuple<byte[], int, int>(bytes, offset, count));
- }
-
- public void Start(CancellationToken cancellationToken)
- {
- while (true)
- {
- foreach (var result in _queue.GetConsumingEnumerable())
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- _outputStream.Write(result.Item1, result.Item2, result.Item3);
- }
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
index ff152c9e9..f3a8a18ee 100644
--- a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
+++ b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
@@ -38,7 +38,7 @@ namespace Emby.Server.Implementations.Notifications
}
catch (Exception ex)
{
- Logger.ErrorException("Error loading notifications database file. Will reset and retry.", ex);
+ Logger.ErrorException("Error loading database file. Will reset and retry.", ex);
FileSystem.DeleteFile(DbFilePath);
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 6f185bc81..97506cdef 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -1406,11 +1406,19 @@ namespace Emby.Server.Implementations.Session
.FirstOrDefault(i => string.Equals(request.Username, i.Name, StringComparison.OrdinalIgnoreCase));
}
- if (user != null && !string.IsNullOrWhiteSpace(request.DeviceId))
+ if (user != null)
{
- if (!_deviceManager.CanAccessDevice(user.Id.ToString("N"), request.DeviceId))
+ if (!user.IsParentalScheduleAllowed())
+ {
+ throw new SecurityException("User is not allowed access at this time.");
+ }
+
+ if (!string.IsNullOrWhiteSpace(request.DeviceId))
{
- throw new SecurityException("User is not allowed access from this device.");
+ if (!_deviceManager.CanAccessDevice(user.Id.ToString("N"), request.DeviceId))
+ {
+ throw new SecurityException("User is not allowed access from this device.");
+ }
}
}
diff --git a/Emby.Server.Implementations/Social/SharingRepository.cs b/Emby.Server.Implementations/Social/SharingRepository.cs
index f306e76c4..f0b8cbd30 100644
--- a/Emby.Server.Implementations/Social/SharingRepository.cs
+++ b/Emby.Server.Implementations/Social/SharingRepository.cs
@@ -7,22 +7,42 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Social;
using SQLitePCL.pretty;
using MediaBrowser.Model.Extensions;
+using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Social
{
public class SharingRepository : BaseSqliteRepository, ISharingRepository
{
- public SharingRepository(ILogger logger, IApplicationPaths appPaths)
+ protected IFileSystem FileSystem { get; private set; }
+
+ public SharingRepository(ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem)
: base(logger)
{
+ FileSystem = fileSystem;
DbFilePath = Path.Combine(appPaths.DataPath, "shares.db");
}
+ public void Initialize()
+ {
+ try
+ {
+ InitializeInternal();
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error loading database file. Will reset and retry.", ex);
+
+ FileSystem.DeleteFile(DbFilePath);
+
+ InitializeInternal();
+ }
+ }
+
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public void Initialize()
+ private void InitializeInternal()
{
using (var connection = CreateConnection())
{
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index 0b81f7e93..ec2d8c4fc 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -56,37 +56,15 @@ namespace Emby.Server.Implementations.TV
return GetResult(GetNextUpEpisodes(request, user, new[] { presentationUniqueKey }, dtoOptions), request);
}
- if (limit.HasValue)
- {
- limit = limit.Value + 10;
- }
-
- var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Episode).Name },
- OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.DatePlayed, SortOrder.Descending) },
- SeriesPresentationUniqueKey = presentationUniqueKey,
- Limit = limit,
- ParentId = parentIdGuid,
- Recursive = true,
- DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions
- {
- Fields = new ItemFields[]
- {
- ItemFields.SeriesPresentationUniqueKey
- }
- },
- GroupBySeriesPresentationUniqueKey = true
-
- }).Cast<Episode>().Select(GetUniqueSeriesKey);
-
- // Avoid implicitly captured closure
- var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
+ var parents = user.RootFolder.GetChildren(user, true)
+ .Where(i => i is Folder)
+ .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N")))
+ .ToList();
- return GetResult(episodes, request);
+ return GetNextUp(request, parents, dtoOptions);
}
- public QueryResult<BaseItem> GetNextUp(NextUpQuery request, List<Folder> parentsFolders, DtoOptions dtoOptions)
+ public QueryResult<BaseItem> GetNextUp(NextUpQuery request, List<BaseItem> parentsFolders, DtoOptions dtoOptions)
{
var user = _userManager.GetUserById(request.UserId);
@@ -134,7 +112,7 @@ namespace Emby.Server.Implementations.TV
},
GroupBySeriesPresentationUniqueKey = true
- }, parentsFolders.Cast<BaseItem>().ToList()).Cast<Episode>().Select(GetUniqueSeriesKey);
+ }, parentsFolders).Cast<Episode>().Select(GetUniqueSeriesKey);
// Avoid implicitly captured closure
var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
diff --git a/Emby.Server.Implementations/packages.config b/Emby.Server.Implementations/packages.config
index c27b8ac26..d27722fef 100644
--- a/Emby.Server.Implementations/packages.config
+++ b/Emby.Server.Implementations/packages.config
@@ -2,7 +2,7 @@
<packages>
<package id="Emby.XmlTv" version="1.0.10" targetFramework="net46" />
<package id="ServiceStack.Text" version="4.5.8" targetFramework="net46" />
- <package id="SharpCompress" version="0.14.0" targetFramework="net46" />
+ <package id="SharpCompress" version="0.18.2" targetFramework="net46" />
<package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
<package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" />
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net46" />
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 5919c50d4..5fe386f1a 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -26,6 +26,11 @@ namespace MediaBrowser.Api.UserLibrary
{
}
+ [Route("/Users/{UserId}/Items/Resume", "GET", Summary = "Gets items based on a query.")]
+ public class GetResumeItems : BaseItemsRequest, IReturn<QueryResult<BaseItemDto>>
+ {
+ }
+
/// <summary>
/// Class ItemsService
/// </summary>
@@ -79,6 +84,53 @@ namespace MediaBrowser.Api.UserLibrary
_authContext = authContext;
}
+ public object Get(GetResumeItems request)
+ {
+ var user = _userManager.GetUserById(request.UserId);
+
+ var parentIdGuid = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId);
+
+ var options = GetDtoOptions(_authContext, request);
+
+ var ancestorIds = new List<string>();
+
+ var excludeFolderIds = user.Configuration.LatestItemsExcludes;
+ if (!parentIdGuid.HasValue && excludeFolderIds.Length > 0)
+ {
+ ancestorIds = user.RootFolder.GetChildren(user, true)
+ .Where(i => i is Folder)
+ .Where(i => !excludeFolderIds.Contains(i.Id.ToString("N")))
+ .Select(i => i.Id.ToString("N"))
+ .ToList();
+ }
+
+ var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
+ {
+ OrderBy = new[] { ItemSortBy.DatePlayed }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
+ IsResumable = true,
+ StartIndex = request.StartIndex,
+ Limit = request.Limit,
+ ParentId = parentIdGuid,
+ Recursive = true,
+ DtoOptions = options,
+ MediaTypes = request.GetMediaTypes(),
+ IsVirtualItem = false,
+ CollapseBoxSetItems = false,
+ EnableTotalRecordCount = request.EnableTotalRecordCount,
+ AncestorIds = ancestorIds.ToArray()
+ });
+
+ var returnItems = _dtoService.GetBaseItemDtos(itemsResult.Items, options, user);
+
+ var result = new QueryResult<BaseItemDto>
+ {
+ TotalRecordCount = itemsResult.TotalRecordCount,
+ Items = returnItems
+ };
+
+ return ToOptimizedSerializedResultUsingCache(result);
+ }
+
/// <summary>
/// Gets the specified request.
/// </summary>
diff --git a/MediaBrowser.Common/Updates/GithubUpdater.cs b/MediaBrowser.Common/Updates/GithubUpdater.cs
index cc83e7c6e..2106ac6d5 100644
--- a/MediaBrowser.Common/Updates/GithubUpdater.cs
+++ b/MediaBrowser.Common/Updates/GithubUpdater.cs
@@ -114,7 +114,7 @@ namespace MediaBrowser.Common.Updates
{
var obj = _jsonSerializer.DeserializeFromStream<RootObject[]>(stream);
- obj = obj.Where(i => (i.assets ?? new List<Asset>()).Any(a => IsAsset(a, assetFilename))).ToArray();
+ obj = obj.Where(i => (i.assets ?? new List<Asset>()).Any(a => IsAsset(a, assetFilename, i.tag_name))).ToArray();
list.AddRange(obj.Where(i => MatchesUpdateLevel(i, PackageVersionClass.Release)).OrderByDescending(GetVersion).Take(1));
list.AddRange(obj.Where(i => MatchesUpdateLevel(i, PackageVersionClass.Beta)).OrderByDescending(GetVersion).Take(1));
@@ -138,7 +138,8 @@ namespace MediaBrowser.Common.Updates
private CheckForUpdateResult CheckForUpdateResult(RootObject obj, Version minVersion, string assetFilename, string packageName, string targetFilename)
{
Version version;
- if (!Version.TryParse(obj.tag_name, out version))
+ var versionString = obj.tag_name;
+ if (!Version.TryParse(versionString, out version))
{
return null;
}
@@ -148,7 +149,7 @@ namespace MediaBrowser.Common.Updates
return null;
}
- var asset = (obj.assets ?? new List<Asset>()).FirstOrDefault(i => IsAsset(i, assetFilename));
+ var asset = (obj.assets ?? new List<Asset>()).FirstOrDefault(i => IsAsset(i, assetFilename, versionString));
if (asset == null)
{
@@ -175,9 +176,22 @@ namespace MediaBrowser.Common.Updates
};
}
- private bool IsAsset(Asset asset, string assetFilename)
+ private bool IsAsset(Asset asset, string assetFilename, string version)
{
- var downloadFilename = Path.GetFileName(asset.browser_download_url) ?? string.Empty;
+ var downloadFilename = Path.GetFileNameWithoutExtension(asset.browser_download_url) ?? string.Empty;
+ var assetExtension = Path.GetExtension(assetFilename);
+
+ assetFilename = assetFilename.Replace("{version}", version);
+ assetFilename = Path.GetFileNameWithoutExtension(assetFilename);
+
+ var zipExtensions = new[] { ".zip", ".7z" };
+ var extensionMatch = zipExtensions.Contains(Path.GetExtension(asset.browser_download_url) ?? string.Empty, StringComparer.OrdinalIgnoreCase) &&
+ zipExtensions.Contains(assetExtension ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+
+ if (!extensionMatch)
+ {
+ return false;
+ }
if (downloadFilename.IndexOf(assetFilename, StringComparison.OrdinalIgnoreCase) != -1)
{
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index 54faa1443..f74c01994 100644
--- a/MediaBrowser.Controller/Channels/Channel.cs
+++ b/MediaBrowser.Controller/Channels/Channel.cs
@@ -32,6 +32,14 @@ namespace MediaBrowser.Controller.Channels
return base.IsVisible(user);
}
+ public override double? GetDefaultPrimaryImageAspectRatio()
+ {
+ double value = 16;
+ value /= 9;
+
+ return value;
+ }
+
[IgnoreDataMember]
public override bool SupportsInheritedParentImages
{
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index d7b68d1e7..542fa5e08 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -117,8 +117,6 @@ namespace MediaBrowser.Controller.Drawing
IImageEncoder ImageEncoder { get; set; }
- void SaveImageSize(string path, DateTime imageDateModified, ImageSize size);
-
bool SupportsTransparency(string path);
}
}
diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs
index 9452446a1..9936b1036 100644
--- a/MediaBrowser.Controller/Drawing/ImageHelper.cs
+++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs
@@ -21,11 +21,6 @@ namespace MediaBrowser.Controller.Drawing
public static IImageProcessor ImageProcessor { get; set; }
- public static void SaveImageSize(string path, DateTime dateModified, ImageSize size)
- {
- ImageProcessor.SaveImageSize(path, dateModified, size);
- }
-
private static ImageSize GetSizeEstimate(ImageProcessingOptions options)
{
if (options.Width.HasValue && options.Height.HasValue)
diff --git a/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs b/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs
index cdb6f3f61..d2b4569ba 100644
--- a/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs
+++ b/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities.Audio
public override double? GetDefaultPrimaryImageAspectRatio()
{
- return null;
+ return 1;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs
index a61862f28..c06f1cef4 100644
--- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs
+++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs
@@ -42,5 +42,13 @@ namespace MediaBrowser.Controller.Entities
return false;
}
}
+
+ //public override double? GetDefaultPrimaryImageAspectRatio()
+ //{
+ // double value = 16;
+ // value /= 9;
+
+ // return value;
+ //}
}
}
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index a83e084db..5fb9e517c 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -31,6 +31,14 @@ namespace MediaBrowser.Controller.Entities
PhysicalFolderIds = EmptyGuidArray;
}
+ //public override double? GetDefaultPrimaryImageAspectRatio()
+ //{
+ // double value = 16;
+ // value /= 9;
+
+ // return value;
+ //}
+
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs
index 4e78a7fa5..6dc85f3e5 100644
--- a/MediaBrowser.Controller/Entities/GameGenre.cs
+++ b/MediaBrowser.Controller/Entities/GameGenre.cs
@@ -22,6 +22,11 @@ namespace MediaBrowser.Controller.Entities
return GetUserDataKeys()[0];
}
+ public override double? GetDefaultPrimaryImageAspectRatio()
+ {
+ return 1;
+ }
+
/// <summary>
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself
diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs
index bbaec14a1..c940b5953 100644
--- a/MediaBrowser.Controller/Entities/GameSystem.cs
+++ b/MediaBrowser.Controller/Entities/GameSystem.cs
@@ -44,6 +44,14 @@ namespace MediaBrowser.Controller.Entities
}
}
+ public override double? GetDefaultPrimaryImageAspectRatio()
+ {
+ double value = 16;
+ value /= 9;
+
+ return value;
+ }
+
/// <summary>
/// Gets or sets the game system.
/// </summary>
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index 790f8938e..569a0dfb8 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -25,6 +25,11 @@ namespace MediaBrowser.Controller.Entities
return GetUserDataKeys()[0];
}
+ public override double? GetDefaultPrimaryImageAspectRatio()
+ {
+ return 1;
+ }
+
/// <summary>
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself
diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs
index 8e9eac50c..11db633ba 100644
--- a/MediaBrowser.Controller/Entities/Photo.cs
+++ b/MediaBrowser.Controller/Entities/Photo.cs
@@ -62,6 +62,35 @@ namespace MediaBrowser.Controller.Entities
return true;
}
+ public override double? GetDefaultPrimaryImageAspectRatio()
+ {
+ if (Width.HasValue && Height.HasValue)
+ {
+ double width = Width.Value;
+ double height = Height.Value;
+
+ if (Orientation.HasValue)
+ {
+ switch (Orientation.Value)
+ {
+ case ImageOrientation.LeftBottom:
+ case ImageOrientation.LeftTop:
+ case ImageOrientation.RightBottom:
+ case ImageOrientation.RightTop:
+ var temp = height;
+ height = width;
+ width = temp;
+ break;
+ }
+ }
+
+ width /= Height.Value;
+ return width;
+ }
+
+ return base.GetDefaultPrimaryImageAspectRatio();
+ }
+
public int? Width { get; set; }
public int? Height { get; set; }
public string CameraMake { get; set; }
diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs
index af9d8c801..52d743e36 100644
--- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs
+++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs
@@ -30,5 +30,10 @@ namespace MediaBrowser.Controller.Entities
return false;
}
}
+
+ public override double? GetDefaultPrimaryImageAspectRatio()
+ {
+ return 1;
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs
index e9a794e79..36bbf6886 100644
--- a/MediaBrowser.Controller/Entities/User.cs
+++ b/MediaBrowser.Controller/Entities/User.cs
@@ -254,6 +254,11 @@ namespace MediaBrowser.Controller.Entities
}
}
+ public override double? GetDefaultPrimaryImageAspectRatio()
+ {
+ return 1;
+ }
+
/// <summary>
/// Gets the configuration directory path.
/// </summary>
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index 66174034d..2152e65cf 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -58,6 +58,14 @@ namespace MediaBrowser.Controller.Entities
}
}
+ //public override double? GetDefaultPrimaryImageAspectRatio()
+ //{
+ // double value = 16;
+ // value /= 9;
+
+ // return value;
+ //}
+
public override int GetChildCount(User user)
{
return GetChildren(user, true).Count;
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index 3ab82a103..43adc4af6 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -238,12 +238,9 @@ namespace MediaBrowser.Controller.Entities
{
if (queryParent is UserView)
{
- return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), queryParent, query);
- }
- else
- {
- return GetResult(queryParent.GetChildren(user, true), queryParent, query);
+ return GetResult(GetMediaFolders(user).OfType<Folder>().SelectMany(i => i.GetChildren(user, true)), queryParent, query);
}
+ return GetResult(queryParent.GetChildren(user, true), queryParent, query);
}
}
}
@@ -1681,7 +1678,7 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- private IEnumerable<Folder> GetMediaFolders(User user)
+ private IEnumerable<BaseItem> GetMediaFolders(User user)
{
if (user == null)
{
@@ -1696,7 +1693,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => user.IsFolderGrouped(i.Id) && UserView.IsEligibleForGrouping(i));
}
- private List<Folder> GetMediaFolders(User user, IEnumerable<string> viewTypes)
+ private List<BaseItem> GetMediaFolders(User user, IEnumerable<string> viewTypes)
{
if (user == null)
{
@@ -1717,14 +1714,14 @@ namespace MediaBrowser.Controller.Entities
}).ToList();
}
- private List<Folder> GetMediaFolders(Folder parent, User user, IEnumerable<string> viewTypes)
+ private List<BaseItem> GetMediaFolders(Folder parent, User user, IEnumerable<string> viewTypes)
{
if (parent == null || parent is UserView)
{
return GetMediaFolders(user, viewTypes);
}
- return new List<Folder> { parent };
+ return new List<BaseItem> { parent };
}
private async Task<QueryResult<BaseItem>> GetLiveTvView(Folder queryParent, User user, InternalItemsQuery query)
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index ffb601dc4..8693d867c 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -78,6 +78,14 @@ namespace MediaBrowser.Controller.Entities
}
}
+ public override double? GetDefaultPrimaryImageAspectRatio()
+ {
+ double value = 16;
+ value /= 9;
+
+ return value;
+ }
+
public override string CreatePresentationUniqueKey()
{
if (!string.IsNullOrWhiteSpace(PrimaryVersionId))
diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs
index 7d820b007..49b967104 100644
--- a/MediaBrowser.Controller/Entities/Year.cs
+++ b/MediaBrowser.Controller/Entities/Year.cs
@@ -32,6 +32,14 @@ namespace MediaBrowser.Controller.Entities
}
}
+ public override double? GetDefaultPrimaryImageAspectRatio()
+ {
+ double value = 2;
+ value /= 3;
+
+ return value;
+ }
+
[IgnoreDataMember]
public override bool SupportsAncestors
{
diff --git a/MediaBrowser.Controller/IO/StreamHelper.cs b/MediaBrowser.Controller/IO/StreamHelper.cs
index af97a0233..106fec41f 100644
--- a/MediaBrowser.Controller/IO/StreamHelper.cs
+++ b/MediaBrowser.Controller/IO/StreamHelper.cs
@@ -6,11 +6,6 @@ namespace MediaBrowser.Controller.IO
{
public static class StreamHelper
{
- public static void CopyTo(Stream source, Stream destination, int bufferSize, CancellationToken cancellationToken)
- {
- CopyTo(source, destination, bufferSize, null, cancellationToken);
- }
-
public static void CopyTo(Stream source, Stream destination, int bufferSize, Action onStarted, CancellationToken cancellationToken)
{
byte[] buffer = new byte[bufferSize];
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index 42c31c629..be85e115c 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -383,7 +383,7 @@ namespace MediaBrowser.Controller.LiveTv
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
string GetEmbyTvActiveRecordingPath(string id);
- Task<LiveStream> GetEmbyTvLiveStream(string id);
+ Task<ILiveStream> GetEmbyTvLiveStream(string id);
ActiveRecordingInfo GetActiveRecordingInfo(string path);
diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
index fc344298b..2019259c5 100644
--- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs
+++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
@@ -36,7 +36,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="streamId">The stream identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
- Task<LiveStream> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
+ Task<ILiveStream> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
/// <summary>
/// Gets the channel stream media sources.
/// </summary>
@@ -56,4 +56,17 @@ namespace MediaBrowser.Controller.LiveTv
/// <returns>Task.</returns>
Task Validate(TunerHostInfo info);
}
+
+ public interface ILiveStream
+ {
+ Task Open(CancellationToken cancellationToken);
+ Task Close();
+ int ConsumerCount { get; }
+ string OriginalStreamId { get; set; }
+ bool EnableStreamSharing { get; set; }
+ ITunerHost TunerHost { get; set; }
+ MediaSourceInfo OpenedMediaSource { get; set; }
+ string UniqueId { get; }
+ List<string> SharedStreamIds { get; }
+ }
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs
deleted file mode 100644
index 20947462e..000000000
--- a/MediaBrowser.Controller/LiveTv/LiveStream.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.System;
-
-namespace MediaBrowser.Controller.LiveTv
-{
- public class LiveStream
- {
- public MediaSourceInfo OriginalMediaSource { get; set; }
- public MediaSourceInfo OpenedMediaSource { get; set; }
- public int ConsumerCount
- {
- get { return SharedStreamIds.Count; }
- }
- public ITunerHost TunerHost { get; set; }
- public string OriginalStreamId { get; set; }
- public bool EnableStreamSharing { get; set; }
- public string UniqueId = Guid.NewGuid().ToString("N");
-
- public List<string> SharedStreamIds = new List<string>();
- protected readonly IEnvironmentInfo Environment;
- protected readonly IFileSystem FileSystem;
- const int StreamCopyToBufferSize = 81920;
-
- public LiveStream(MediaSourceInfo mediaSource, IEnvironmentInfo environment, IFileSystem fileSystem)
- {
- OriginalMediaSource = mediaSource;
- Environment = environment;
- FileSystem = fileSystem;
- OpenedMediaSource = mediaSource;
- EnableStreamSharing = true;
- }
-
- public Task Open(CancellationToken cancellationToken)
- {
- return OpenInternal(cancellationToken);
- }
-
- protected virtual Task OpenInternal(CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
-
- public virtual Task Close()
- {
- return Task.FromResult(true);
- }
-
- protected Stream GetInputStream(string path, bool allowAsyncFileRead)
- {
- var fileOpenOptions = FileOpenOptions.SequentialScan;
-
- if (allowAsyncFileRead)
- {
- fileOpenOptions |= FileOpenOptions.Asynchronous;
- }
-
- return FileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, fileOpenOptions);
- }
-
- protected async Task DeleteTempFile(string path, int retryCount = 0)
- {
- try
- {
- FileSystem.DeleteFile(path);
- return;
- }
- catch
- {
-
- }
-
- if (retryCount > 20)
- {
- return;
- }
-
- await Task.Delay(500).ConfigureAwait(false);
- await DeleteTempFile(path, retryCount + 1).ConfigureAwait(false);
- }
- }
-}
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 5ef763b62..b33993859 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -145,7 +145,6 @@
<Compile Include="Library\UserDataSaveEventArgs.cs" />
<Compile Include="LiveTv\IListingsProvider.cs" />
<Compile Include="LiveTv\ITunerHost.cs" />
- <Compile Include="LiveTv\LiveStream.cs" />
<Compile Include="LiveTv\RecordingGroup.cs" />
<Compile Include="LiveTv\RecordingStatusChangedEventArgs.cs" />
<Compile Include="LiveTv\ILiveTvRecording.cs" />
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 657b9c959..8b612f809 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -346,7 +346,8 @@ namespace MediaBrowser.Controller.MediaEncoding
"Constrained High"
};
- return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase));
+ // strip spaces because they may be stripped out on the query string
+ return Array.FindIndex(list.ToArray(), t => string.Equals(t.Replace(" ", ""), profile.Replace(" ", ""), StringComparison.OrdinalIgnoreCase));
}
public string GetInputPathArgument(EncodingJobInfo state)
@@ -529,7 +530,8 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var seconds = Math.Round(TimeSpan.FromTicks(state.StartTimeTicks ?? 0).TotalSeconds);
- var setPtsParam = state.CopyTimestamps
+ // hls always copies timestamps
+ var setPtsParam = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive
? string.Empty
: string.Format(",setpts=PTS -{0}/TB", seconds.ToString(_usCulture));
@@ -691,22 +693,26 @@ namespace MediaBrowser.Controller.MediaEncoding
param += string.Format(" -r {0}", framerate.Value.ToString(_usCulture));
}
- var request = state.BaseRequest;
+ var targetVideoCodec = state.ActualOutputVideoCodec;
- if (!string.IsNullOrEmpty(request.Profile))
+ var request = state.BaseRequest;
+ var profile = state.GetRequestedProfiles(targetVideoCodec).FirstOrDefault();
+ if (!string.IsNullOrEmpty(profile))
{
if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
{
// not supported by h264_omx
- param += " -profile:v " + request.Profile;
+ param += " -profile:v " + profile;
}
}
- if (!string.IsNullOrEmpty(request.Level))
+ var level = state.GetRequestedLevel(targetVideoCodec);
+
+ if (!string.IsNullOrEmpty(level))
{
- var level = NormalizeTranscodingLevel(state.OutputVideoCodec, request.Level);
+ level = NormalizeTranscodingLevel(state.OutputVideoCodec, level);
// h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
// also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307
@@ -756,7 +762,6 @@ namespace MediaBrowser.Controller.MediaEncoding
{
param += " -level " + level;
}
-
}
if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
@@ -796,7 +801,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (videoStream.IsInterlaced)
{
- if (request.DeInterlace)
+ if (state.DeInterlace(videoStream.Codec, false))
{
return false;
}
@@ -828,23 +833,27 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// Source and target codecs must match
- if (string.IsNullOrEmpty(videoStream.Codec) || !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparer.OrdinalIgnoreCase))
+ if (string.IsNullOrWhiteSpace(videoStream.Codec) || !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparer.OrdinalIgnoreCase))
{
return false;
}
+ var requestedProfiles = state.GetRequestedProfiles(videoStream.Codec);
+
// If client is requesting a specific video profile, it must match the source
- if (!string.IsNullOrEmpty(request.Profile))
+ if (requestedProfiles.Length > 0)
{
- if (string.IsNullOrEmpty(videoStream.Profile))
+ if (string.IsNullOrWhiteSpace(videoStream.Profile))
{
//return false;
}
- if (!string.IsNullOrEmpty(videoStream.Profile) && !string.Equals(request.Profile, videoStream.Profile, StringComparison.OrdinalIgnoreCase))
+ var requestedProfile = requestedProfiles[0];
+ // strip spaces because they may be stripped out on the query string as well
+ if (!string.IsNullOrWhiteSpace(videoStream.Profile) && !requestedProfiles.Contains(videoStream.Profile.Replace(" ", ""), StringComparer.OrdinalIgnoreCase))
{
var currentScore = GetVideoProfileScore(videoStream.Profile);
- var requestedScore = GetVideoProfileScore(request.Profile);
+ var requestedScore = GetVideoProfileScore(requestedProfile);
if (currentScore == -1 || currentScore > requestedScore)
{
@@ -909,11 +918,12 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// If a specific level was requested, the source must match or be less than
- if (!string.IsNullOrEmpty(request.Level))
+ var level = state.GetRequestedLevel(videoStream.Codec);
+ if (!string.IsNullOrEmpty(level))
{
double requestLevel;
- if (double.TryParse(request.Level, NumberStyles.Any, _usCulture, out requestLevel))
+ if (double.TryParse(level, NumberStyles.Any, _usCulture, out requestLevel))
{
if (!videoStream.Level.HasValue)
{
@@ -1074,7 +1084,8 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode && !state.CopyTimestamps)
+ var isCopyingTimestamps = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive;
+ if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode && !isCopyingTimestamps)
{
var seconds = TimeSpan.FromTicks(state.StartTimeTicks ?? 0).TotalSeconds;
@@ -1357,9 +1368,10 @@ namespace MediaBrowser.Controller.MediaEncoding
filters.Add("hwupload");
}
- if (state.DeInterlace && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+ if (state.DeInterlace("h264", true) && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
- if (string.Equals(options.DeinterlaceMethod, "bobandweave", StringComparison.OrdinalIgnoreCase))
+ // If it is already 60fps then it will create an output framerate that is much too high for roku and others to handle
+ if (string.Equals(options.DeinterlaceMethod, "bobandweave", StringComparison.OrdinalIgnoreCase) && (state.VideoStream.RealFrameRate ?? 60) <= 30)
{
filters.Add("yadif=1:-1:0");
}
@@ -1523,11 +1535,18 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <returns>System.Int32.</returns>
public int GetNumberOfThreads(EncodingJobInfo state, EncodingOptions encodingOptions, bool isWebm)
{
- var threads = GetNumberOfThreadsInternal(state, encodingOptions, isWebm);
+ if (isWebm)
+ {
+ // Recommended per docs
+ return Math.Max(Environment.ProcessorCount - 1, 2);
+ }
+
+ var threads = state.BaseRequest.CpuCoreLimit ?? encodingOptions.EncodingThreadCount;
- if (state.BaseRequest.CpuCoreLimit.HasValue && state.BaseRequest.CpuCoreLimit.Value > 0)
+ // Automatic
+ if (threads <= 0 || threads >= Environment.ProcessorCount)
{
- threads = Math.Min(threads, state.BaseRequest.CpuCoreLimit.Value);
+ return 0;
}
return threads;
@@ -1799,11 +1818,6 @@ namespace MediaBrowser.Controller.MediaEncoding
state.InternalSubtitleStreamOffset = mediaStreams.Where(i => i.Type == MediaStreamType.Subtitle && !i.IsExternal).ToList().IndexOf(state.SubtitleStream);
}
- if (state.VideoStream != null && state.VideoStream.IsInterlaced)
- {
- state.DeInterlace = true;
- }
-
EnforceResolutionLimit(state);
NormalizeSubtitleEmbed(state);
@@ -1954,29 +1968,6 @@ namespace MediaBrowser.Controller.MediaEncoding
return null;
}
- /// <summary>
- /// Gets the number of threads.
- /// </summary>
- /// <returns>System.Int32.</returns>
- private int GetNumberOfThreadsInternal(EncodingJobInfo state, EncodingOptions encodingOptions, bool isWebm)
- {
- var threads = encodingOptions.EncodingThreadCount;
-
- if (isWebm)
- {
- // Recommended per docs
- return Math.Max(Environment.ProcessorCount - 1, 2);
- }
-
- // Automatic
- if (threads == -1)
- {
- return 0;
- }
-
- return threads;
- }
-
public string GetSubtitleEmbedArguments(EncodingJobInfo state)
{
if (state.SubtitleStream == null || state.SubtitleDeliveryMethod != SubtitleDeliveryMethod.Embed)
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
index e76217fda..506fce3ca 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -160,7 +160,97 @@ namespace MediaBrowser.Controller.MediaEncoding
public int? OutputAudioBitrate;
public int? OutputAudioChannels;
- public bool DeInterlace { get; set; }
+
+ public bool DeInterlace(string videoCodec, bool forceDeinterlaceIfSourceIsInterlaced)
+ {
+ var videoStream = VideoStream;
+ var isInputInterlaced = videoStream != null && videoStream.IsInterlaced;
+
+ if (!isInputInterlaced)
+ {
+ return false;
+ }
+
+ // Support general param
+ if (BaseRequest.DeInterlace)
+ {
+ return true;
+ }
+
+ if (!string.IsNullOrWhiteSpace(videoCodec))
+ {
+ if (string.Equals(BaseRequest.GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+
+ if (forceDeinterlaceIfSourceIsInterlaced)
+ {
+ if (isInputInterlaced)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public string[] GetRequestedProfiles(string codec)
+ {
+ if (!string.IsNullOrWhiteSpace(BaseRequest.Profile))
+ {
+ return BaseRequest.Profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries);
+ }
+
+ if (!string.IsNullOrWhiteSpace(codec))
+ {
+ var profile = BaseRequest.GetOption(codec, "profile");
+
+ if (!string.IsNullOrWhiteSpace(profile))
+ {
+ return profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries);
+ }
+ }
+
+ return new string[] { };
+ }
+
+ public string GetRequestedLevel(string codec)
+ {
+ if (!string.IsNullOrWhiteSpace(BaseRequest.Level))
+ {
+ return BaseRequest.Level;
+ }
+
+ if (!string.IsNullOrWhiteSpace(codec))
+ {
+ return BaseRequest.GetOption(codec, "level");
+ }
+
+ return null;
+ }
+
+ public int? GetRequestedMaxRefFrames(string codec)
+ {
+ if (!string.IsNullOrWhiteSpace(BaseRequest.Level))
+ {
+ return BaseRequest.MaxRefFrames;
+ }
+
+ if (!string.IsNullOrWhiteSpace(codec))
+ {
+ var value = BaseRequest.GetOption(codec, "maxrefframes");
+ int result;
+ if (!string.IsNullOrWhiteSpace(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+ {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
public bool IsVideoRequest { get; set; }
public TranscodingJobType TranscodingType { get; set; }
@@ -169,7 +259,7 @@ namespace MediaBrowser.Controller.MediaEncoding
_logger = logger;
TranscodingType = jobType;
RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- PlayableStreamFileNames = new string[]{};
+ PlayableStreamFileNames = new string[] { };
SupportedAudioCodecs = new List<string>();
SupportedVideoCodecs = new List<string>();
SupportedSubtitleCodecs = new List<string>();
@@ -319,12 +409,19 @@ namespace MediaBrowser.Controller.MediaEncoding
{
get
{
- var stream = VideoStream;
- var request = BaseRequest;
+ if (BaseRequest.Static)
+ {
+ return VideoStream == null ? null : VideoStream.Level;
+ }
- return !string.IsNullOrEmpty(request.Level) && !request.Static
- ? double.Parse(request.Level, CultureInfo.InvariantCulture)
- : stream == null ? null : stream.Level;
+ var level = GetRequestedLevel(ActualOutputVideoCodec);
+ double result;
+ if (!string.IsNullOrWhiteSpace(level) && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+ {
+ return result;
+ }
+
+ return null;
}
}
@@ -348,8 +445,12 @@ namespace MediaBrowser.Controller.MediaEncoding
{
get
{
- var stream = VideoStream;
- return stream == null || !BaseRequest.Static ? null : stream.RefFrames;
+ if (BaseRequest.Static)
+ {
+ return VideoStream == null ? null : VideoStream.RefFrames;
+ }
+
+ return null;
}
}
@@ -404,10 +505,18 @@ namespace MediaBrowser.Controller.MediaEncoding
{
get
{
- var stream = VideoStream;
- return !string.IsNullOrEmpty(BaseRequest.Profile) && !BaseRequest.Static
- ? BaseRequest.Profile
- : stream == null ? null : stream.Profile;
+ if (BaseRequest.Static)
+ {
+ return VideoStream == null ? null : VideoStream.Profile;
+ }
+
+ var requestedProfile = GetRequestedProfiles(ActualOutputVideoCodec).FirstOrDefault();
+ if (!string.IsNullOrWhiteSpace(requestedProfile))
+ {
+ return requestedProfile;
+ }
+
+ return null;
}
}
@@ -435,6 +544,28 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
+ public string ActualOutputVideoCodec
+ {
+ get
+ {
+ var codec = OutputVideoCodec;
+
+ if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ var stream = VideoStream;
+
+ if (stream != null)
+ {
+ return stream.Codec;
+ }
+
+ return null;
+ }
+
+ return codec;
+ }
+ }
+
public bool? IsTargetInterlaced
{
get
@@ -444,7 +575,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return VideoStream == null ? (bool?)null : VideoStream.IsInterlaced;
}
- if (DeInterlace)
+ if (DeInterlace(ActualOutputVideoCodec, true))
{
return false;
}
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
index 5fc93bf38..bac2a6e65 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
@@ -1,4 +1,7 @@
-using System.Globalization;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Services;
@@ -37,18 +40,16 @@ namespace MediaBrowser.Controller.MediaEncoding
MaxWidth = info.MaxWidth;
MaxHeight = info.MaxHeight;
MaxFramerate = info.MaxFramerate;
- Profile = info.VideoProfile;
ItemId = info.ItemId;
MediaSourceId = info.MediaSourceId;
- AudioCodec = info.TargetAudioCodec;
+ AudioCodec = info.TargetAudioCodec.FirstOrDefault();
MaxAudioChannels = info.MaxAudioChannels;
AudioBitRate = info.AudioBitrate;
AudioSampleRate = info.TargetAudioSampleRate;
DeviceProfile = deviceProfile;
- VideoCodec = info.TargetVideoCodec;
+ VideoCodec = info.TargetVideoCodec.FirstOrDefault();
VideoBitRate = info.VideoBitrate;
AudioStreamIndex = info.AudioStreamIndex;
- MaxRefFrames = info.MaxRefFrames;
MaxVideoBitDepth = info.MaxVideoBitDepth;
SubtitleMethod = info.SubtitleDeliveryMethod;
Context = info.Context;
@@ -58,11 +59,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
SubtitleStreamIndex = info.SubtitleStreamIndex;
}
-
- if (info.VideoLevel.HasValue)
- {
- Level = info.VideoLevel.Value.ToString(_usCulture);
- }
+ StreamOptions = info.StreamOptions;
}
}
@@ -224,12 +221,41 @@ namespace MediaBrowser.Controller.MediaEncoding
public EncodingContext Context { get; set; }
+ public void SetOption(string qualifier, string name, string value)
+ {
+ SetOption(qualifier + "-" + name, value);
+ }
+
+ public Dictionary<string, string> StreamOptions { get; set; }
+
+ public void SetOption(string name, string value)
+ {
+ StreamOptions[name] = value;
+ }
+
+ public string GetOption(string qualifier, string name)
+ {
+ return GetOption(qualifier + "-" + name);
+ }
+
+ public string GetOption(string name)
+ {
+ string value;
+ if (StreamOptions.TryGetValue(name, out value))
+ {
+ return value;
+ }
+
+ return null;
+ }
+
public BaseEncodingJobOptions()
{
EnableAutoStreamCopy = true;
AllowVideoStreamCopy = true;
AllowAudioStreamCopy = true;
Context = EncodingContext.Streaming;
+ StreamOptions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
}
}
diff --git a/MediaBrowser.Controller/TV/ITVSeriesManager.cs b/MediaBrowser.Controller/TV/ITVSeriesManager.cs
index 0bcb9ae5b..fd41094ee 100644
--- a/MediaBrowser.Controller/TV/ITVSeriesManager.cs
+++ b/MediaBrowser.Controller/TV/ITVSeriesManager.cs
@@ -15,6 +15,6 @@ namespace MediaBrowser.Controller.TV
/// <summary>
/// Gets the next up.
/// </summary>
- QueryResult<BaseItem> GetNextUp(NextUpQuery request, List<Folder> parentsFolders, DtoOptions options);
+ QueryResult<BaseItem> GetNextUp(NextUpQuery request, List<BaseItem> parentsFolders, DtoOptions options);
}
}
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index a143bb9e3..fbc5e1b37 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -25,7 +25,8 @@ namespace MediaBrowser.Model.Configuration
EnableThrottling = true;
ThrottleDelaySeconds = 180;
EncodingThreadCount = -1;
- VaapiDevice = "/dev/dri/card0";
+ // This is a DRM device that is almost guaranteed to be there on every intel platform, plus it's the default one in ffmpeg if you don't specify anything
+ VaapiDevice = "/dev/dri/renderD128";
H264Crf = 23;
EnableHardwareEncoding = true;
EnableSubtitleExtraction = true;
diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs
index 9cd656fa7..07a821baf 100644
--- a/MediaBrowser.Model/Configuration/LibraryOptions.cs
+++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs
@@ -30,6 +30,8 @@
/// <value>The metadata country code.</value>
public string MetadataCountryCode { get; set; }
+ public string SeasonZeroDisplayName { get; set; }
+
public LibraryOptions()
{
EnablePhotos = true;
@@ -37,6 +39,7 @@
PathInfos = new MediaPathInfo[] { };
EnableInternetProviders = true;
EnableAutomaticSeriesGrouping = true;
+ SeasonZeroDisplayName = "Specials";
}
}
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index ae04bbaab..f7fffbf79 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -78,12 +78,6 @@ namespace MediaBrowser.Model.Configuration
public string MetadataNetworkPath { get; set; }
/// <summary>
- /// Gets or sets the display name of the season zero.
- /// </summary>
- /// <value>The display name of the season zero.</value>
- public string SeasonZeroDisplayName { get; set; }
-
- /// <summary>
/// Gets or sets the preferred metadata language.
/// </summary>
/// <value>The preferred metadata language.</value>
@@ -187,6 +181,8 @@ namespace MediaBrowser.Model.Configuration
public string[] CodecsUsed { get; set; }
public bool EnableChannelView { get; set; }
public bool EnableExternalContentInSuggestions { get; set; }
+ public bool RequireHttps { get; set; }
+ public bool IsBehindProxy { get; set; }
public int ImageExtractionTimeoutMs { get; set; }
@@ -239,8 +235,6 @@ namespace MediaBrowser.Model.Configuration
SortRemoveCharacters = new[] { ",", "&", "-", "{", "}", "'" };
SortRemoveWords = new[] { "the", "a", "an" };
- SeasonZeroDisplayName = "Specials";
-
UICulture = "en-us";
MetadataOptions = new[]
diff --git a/MediaBrowser.Model/Dlna/CodecProfile.cs b/MediaBrowser.Model/Dlna/CodecProfile.cs
index d75547adb..6d143962d 100644
--- a/MediaBrowser.Model/Dlna/CodecProfile.cs
+++ b/MediaBrowser.Model/Dlna/CodecProfile.cs
@@ -36,7 +36,12 @@ namespace MediaBrowser.Model.Dlna
return ContainerProfile.ContainsContainer(Container, container);
}
- public bool ContainsCodec(string codec, string container)
+ public bool ContainsAnyCodec(string codec, string container)
+ {
+ return ContainsAnyCodec(ContainerProfile.SplitValue(codec), container);
+ }
+
+ public bool ContainsAnyCodec(string[] codec, string container)
{
if (!ContainsContainer(container))
{
@@ -44,8 +49,20 @@ namespace MediaBrowser.Model.Dlna
}
var codecs = GetCodecs();
+ if (codecs.Length == 0)
+ {
+ return true;
+ }
+
+ foreach (var val in codec)
+ {
+ if (ListHelper.ContainsIgnoreCase(codecs, val))
+ {
+ return true;
+ }
+ }
- return codecs.Length == 0 || ListHelper.ContainsIgnoreCase(codecs, ContainerProfile.SplitValue(codec)[0]);
+ return false;
}
}
}
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index a5ec0f26c..95a80c34c 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -283,7 +283,7 @@ namespace MediaBrowser.Model.Dlna
var conditions = new List<ProfileCondition>();
foreach (CodecProfile i in options.Profile.CodecProfiles)
{
- if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec, item.Container))
+ if (i.Type == CodecType.Audio && i.ContainsAnyCodec(audioCodec, item.Container))
{
bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions)
@@ -375,7 +375,7 @@ namespace MediaBrowser.Model.Dlna
var audioCodecProfiles = new List<CodecProfile>();
foreach (CodecProfile i in options.Profile.CodecProfiles)
{
- if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
+ if (i.Type == CodecType.Audio && i.ContainsAnyCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
{
audioCodecProfiles.Add(i);
}
@@ -406,7 +406,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- ApplyTranscodingConditions(playlistItem, audioTranscodingConditions);
+ ApplyTranscodingConditions(playlistItem, audioTranscodingConditions, null, false);
// Honor requested max channels
if (options.MaxAudioChannels.HasValue)
@@ -769,24 +769,36 @@ namespace MediaBrowser.Model.Dlna
playlistItem.AudioStreamIndex = audioStreamIndex;
ConditionProcessor conditionProcessor = new ConditionProcessor();
- var videoTranscodingConditions = new List<ProfileCondition>();
+ var isFirstAppliedCodecProfile = true;
foreach (CodecProfile i in options.Profile.CodecProfiles)
{
- if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec, transcodingProfile.Container))
+ if (i.Type == CodecType.Video && i.ContainsAnyCodec(transcodingProfile.VideoCodec, transcodingProfile.Container))
{
bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions)
{
- bool? isSecondaryAudio = audioStream == null ? null : item.IsSecondaryAudio(audioStream);
- int? inputAudioBitrate = audioStream == null ? null : audioStream.BitRate;
- int? audioChannels = audioStream == null ? null : audioStream.Channels;
- string audioProfile = audioStream == null ? null : audioStream.Profile;
- int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate;
- int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth;
+ int? width = videoStream == null ? null : videoStream.Width;
+ int? height = videoStream == null ? null : videoStream.Height;
+ int? bitDepth = videoStream == null ? null : videoStream.BitDepth;
+ int? videoBitrate = videoStream == null ? null : videoStream.BitRate;
+ double? videoLevel = videoStream == null ? null : videoStream.Level;
+ string videoProfile = videoStream == null ? null : videoStream.Profile;
+ float? videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate;
+ bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic;
+ bool? isInterlaced = videoStream == null ? (bool?)null : videoStream.IsInterlaced;
+ string videoCodecTag = videoStream == null ? null : videoStream.CodecTag;
+ bool? isAvc = videoStream == null ? null : videoStream.IsAVC;
- if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))
+ TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp;
+ int? packetLength = videoStream == null ? null : videoStream.PacketLength;
+ int? refFrames = videoStream == null ? null : videoStream.RefFrames;
+
+ int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
+ int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video);
+
+ if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
- LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item);
+ LogConditionFailure(options.Profile, "VideoCodecProfile", applyCondition, item);
applyConditions = false;
break;
}
@@ -794,44 +806,35 @@ namespace MediaBrowser.Model.Dlna
if (applyConditions)
{
- foreach (ProfileCondition c in i.Conditions)
+ var transcodingVideoCodecs = ContainerProfile.SplitValue(transcodingProfile.VideoCodec);
+ foreach (var transcodingVideoCodec in transcodingVideoCodecs)
{
- videoTranscodingConditions.Add(c);
+ if (i.ContainsAnyCodec(transcodingVideoCodec, transcodingProfile.Container))
+ {
+ ApplyTranscodingConditions(playlistItem, i.Conditions, transcodingVideoCodec, !isFirstAppliedCodecProfile);
+ isFirstAppliedCodecProfile = false;
+ }
}
- break;
}
}
}
- ApplyTranscodingConditions(playlistItem, videoTranscodingConditions);
var audioTranscodingConditions = new List<ProfileCondition>();
foreach (CodecProfile i in options.Profile.CodecProfiles)
{
- if (i.Type == CodecType.VideoAudio && i.ContainsCodec(playlistItem.TargetAudioCodec, transcodingProfile.Container))
+ if (i.Type == CodecType.VideoAudio && i.ContainsAnyCodec(playlistItem.TargetAudioCodec, transcodingProfile.Container))
{
bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions)
{
- int? width = videoStream == null ? null : videoStream.Width;
- int? height = videoStream == null ? null : videoStream.Height;
- int? bitDepth = videoStream == null ? null : videoStream.BitDepth;
- int? videoBitrate = videoStream == null ? null : videoStream.BitRate;
- double? videoLevel = videoStream == null ? null : videoStream.Level;
- string videoProfile = videoStream == null ? null : videoStream.Profile;
- float? videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate;
- bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic;
- bool? isInterlaced = videoStream == null ? (bool?)null : videoStream.IsInterlaced;
- string videoCodecTag = videoStream == null ? null : videoStream.CodecTag;
- bool? isAvc = videoStream == null ? null : videoStream.IsAVC;
-
- TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp;
- int? packetLength = videoStream == null ? null : videoStream.PacketLength;
- int? refFrames = videoStream == null ? null : videoStream.RefFrames;
-
- int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
- int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video);
+ bool? isSecondaryAudio = audioStream == null ? null : item.IsSecondaryAudio(audioStream);
+ int? inputAudioBitrate = audioStream == null ? null : audioStream.BitRate;
+ int? audioChannels = audioStream == null ? null : audioStream.Channels;
+ string audioProfile = audioStream == null ? null : audioStream.Profile;
+ int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate;
+ int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth;
- if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
+ if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))
{
LogConditionFailure(options.Profile, "VideoCodecProfile", applyCondition, item);
applyConditions = false;
@@ -878,7 +881,7 @@ namespace MediaBrowser.Model.Dlna
}
// Do this after initial values are set to account for greater than/less than conditions
- ApplyTranscodingConditions(playlistItem, audioTranscodingConditions);
+ ApplyTranscodingConditions(playlistItem, audioTranscodingConditions, null, false);
}
playlistItem.TranscodeReasons = transcodeReasons;
@@ -896,8 +899,10 @@ namespace MediaBrowser.Model.Dlna
return 192000;
}
- private int GetAudioBitrate(string subProtocol, long? maxTotalBitrate, int? targetAudioChannels, string targetAudioCodec, MediaStream audioStream)
+ private int GetAudioBitrate(string subProtocol, long? maxTotalBitrate, int? targetAudioChannels, string[] targetAudioCodecs, MediaStream audioStream)
{
+ var targetAudioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
+
int defaultBitrate = audioStream == null ? 192000 : audioStream.BitRate ?? GetDefaultAudioBitrateIfUnknown(audioStream);
// Reduce the bitrate if we're downmixing
@@ -1061,7 +1066,7 @@ namespace MediaBrowser.Model.Dlna
conditions = new List<ProfileCondition>();
foreach (CodecProfile i in profile.CodecProfiles)
{
- if (i.Type == CodecType.Video && i.ContainsCodec(videoCodec, container))
+ if (i.Type == CodecType.Video && i.ContainsAnyCodec(videoCodec, container))
{
bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions)
@@ -1117,7 +1122,7 @@ namespace MediaBrowser.Model.Dlna
foreach (CodecProfile i in profile.CodecProfiles)
{
- if (i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec, container))
+ if (i.Type == CodecType.VideoAudio && i.ContainsAnyCodec(audioCodec, container))
{
bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions)
@@ -1257,13 +1262,13 @@ namespace MediaBrowser.Model.Dlna
}
// Look for an external or hls profile that matches the stream type (text/graphical) and doesn't require conversion
- return GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, false) ??
- GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, true) ??
+ return GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, false) ??
+ GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, true) ??
new SubtitleProfile
- {
- Method = SubtitleDeliveryMethod.Encode,
- Format = subtitleStream.Codec
- };
+ {
+ Method = SubtitleDeliveryMethod.Encode,
+ Format = subtitleStream.Codec
+ };
}
private static bool IsSubtitleEmbedSupported(MediaStream subtitleStream, SubtitleProfile subtitleProfile, string transcodingSubProtocol, string transcodingContainer)
@@ -1407,7 +1412,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- private void ApplyTranscodingConditions(StreamInfo item, IEnumerable<ProfileCondition> conditions)
+ private void ApplyTranscodingConditions(StreamInfo item, IEnumerable<ProfileCondition> conditions, string qualifier, bool qualifiedOnly)
{
foreach (ProfileCondition condition in conditions)
{
@@ -1428,6 +1433,11 @@ namespace MediaBrowser.Model.Dlna
{
case ProfileConditionValue.AudioBitrate:
{
+ if (qualifiedOnly)
+ {
+ continue;
+ }
+
int num;
if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out num))
{
@@ -1448,6 +1458,11 @@ namespace MediaBrowser.Model.Dlna
}
case ProfileConditionValue.AudioChannels:
{
+ if (qualifiedOnly)
+ {
+ continue;
+ }
+
int num;
if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out num))
{
@@ -1468,6 +1483,11 @@ namespace MediaBrowser.Model.Dlna
}
case ProfileConditionValue.IsAvc:
{
+ if (qualifiedOnly)
+ {
+ continue;
+ }
+
bool isAvc;
if (bool.TryParse(value, out isAvc))
{
@@ -1484,6 +1504,11 @@ namespace MediaBrowser.Model.Dlna
}
case ProfileConditionValue.IsAnamorphic:
{
+ if (qualifiedOnly)
+ {
+ continue;
+ }
+
bool isAnamorphic;
if (bool.TryParse(value, out isAnamorphic))
{
@@ -1500,16 +1525,21 @@ namespace MediaBrowser.Model.Dlna
}
case ProfileConditionValue.IsInterlaced:
{
+ if (string.IsNullOrWhiteSpace(qualifier))
+ {
+ continue;
+ }
+
bool isInterlaced;
if (bool.TryParse(value, out isInterlaced))
{
if (!isInterlaced && condition.Condition == ProfileConditionType.Equals)
{
- item.DeInterlace = true;
+ item.SetOption(qualifier, "deinterlace", "true");
}
else if (isInterlaced && condition.Condition == ProfileConditionType.NotEquals)
{
- item.DeInterlace = true;
+ item.SetOption(qualifier, "deinterlace", "true");
}
}
break;
@@ -1527,26 +1557,36 @@ namespace MediaBrowser.Model.Dlna
}
case ProfileConditionValue.RefFrames:
{
+ if (string.IsNullOrWhiteSpace(qualifier))
+ {
+ continue;
+ }
+
int num;
if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out num))
{
if (condition.Condition == ProfileConditionType.Equals)
{
- item.MaxRefFrames = num;
+ item.SetOption(qualifier, "maxrefframes", StringHelper.ToStringCultureInvariant(num));
}
else if (condition.Condition == ProfileConditionType.LessThanEqual)
{
- item.MaxRefFrames = Math.Min(num, item.MaxRefFrames ?? num);
+ item.SetOption(qualifier, "maxrefframes", StringHelper.ToStringCultureInvariant(Math.Min(num, item.GetTargetRefFrames(qualifier) ?? num)));
}
else if (condition.Condition == ProfileConditionType.GreaterThanEqual)
{
- item.MaxRefFrames = Math.Max(num, item.MaxRefFrames ?? num);
+ item.SetOption(qualifier, "maxrefframes", StringHelper.ToStringCultureInvariant(Math.Max(num, item.GetTargetRefFrames(qualifier) ?? num)));
}
}
break;
}
case ProfileConditionValue.VideoBitDepth:
{
+ if (qualifiedOnly)
+ {
+ continue;
+ }
+
int num;
if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out num))
{
@@ -1567,11 +1607,30 @@ namespace MediaBrowser.Model.Dlna
}
case ProfileConditionValue.VideoProfile:
{
- item.VideoProfile = (value ?? string.Empty).Split('|')[0];
+ if (string.IsNullOrWhiteSpace(qualifier))
+ {
+ continue;
+ }
+
+ if (!string.IsNullOrWhiteSpace(value))
+ {
+ // change from split by | to comma
+
+ // strip spaces to avoid having to encode
+ var values = value
+ .Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+
+ item.SetOption(qualifier, "profile", string.Join(",", values));
+ }
break;
}
case ProfileConditionValue.Height:
{
+ if (qualifiedOnly)
+ {
+ continue;
+ }
+
int num;
if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out num))
{
@@ -1592,6 +1651,11 @@ namespace MediaBrowser.Model.Dlna
}
case ProfileConditionValue.VideoBitrate:
{
+ if (qualifiedOnly)
+ {
+ continue;
+ }
+
int num;
if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out num))
{
@@ -1612,6 +1676,11 @@ namespace MediaBrowser.Model.Dlna
}
case ProfileConditionValue.VideoFramerate:
{
+ if (qualifiedOnly)
+ {
+ continue;
+ }
+
float num;
if (float.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out num))
{
@@ -1632,26 +1701,36 @@ namespace MediaBrowser.Model.Dlna
}
case ProfileConditionValue.VideoLevel:
{
+ if (string.IsNullOrWhiteSpace(qualifier))
+ {
+ continue;
+ }
+
int num;
if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out num))
{
if (condition.Condition == ProfileConditionType.Equals)
{
- item.VideoLevel = num;
+ item.SetOption(qualifier, "level", StringHelper.ToStringCultureInvariant(num));
}
else if (condition.Condition == ProfileConditionType.LessThanEqual)
{
- item.VideoLevel = Math.Min(num, item.VideoLevel ?? num);
+ item.SetOption(qualifier, "level", StringHelper.ToStringCultureInvariant(Math.Min(num, item.GetTargetVideoLevel(qualifier) ?? num)));
}
else if (condition.Condition == ProfileConditionType.GreaterThanEqual)
{
- item.VideoLevel = Math.Max(num, item.VideoLevel ?? num);
+ item.SetOption(qualifier, "level", StringHelper.ToStringCultureInvariant(Math.Max(num, item.GetTargetVideoLevel(qualifier) ?? num)));
}
}
break;
}
case ProfileConditionValue.Width:
{
+ if (qualifiedOnly)
+ {
+ continue;
+ }
+
int num;
if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out num))
{
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index c63e74eaf..5a059e91d 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -22,6 +22,33 @@ namespace MediaBrowser.Model.Dlna
VideoCodecs = new string[] { };
SubtitleCodecs = new string[] { };
TranscodeReasons = new List<TranscodeReason>();
+ StreamOptions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ }
+
+ public void SetOption(string qualifier, string name, string value)
+ {
+ SetOption(qualifier + "-" + name, value);
+ }
+
+ public void SetOption(string name, string value)
+ {
+ StreamOptions[name] = value;
+ }
+
+ public string GetOption(string qualifier, string name)
+ {
+ return GetOption(qualifier + "-" + name);
+ }
+
+ public string GetOption(string name)
+ {
+ string value;
+ if (StreamOptions.TryGetValue(name, out value))
+ {
+ return value;
+ }
+
+ return null;
}
public string ItemId { get; set; }
@@ -37,14 +64,11 @@ namespace MediaBrowser.Model.Dlna
public long StartPositionTicks { get; set; }
- public string VideoProfile { get; set; }
-
public int? SegmentLength { get; set; }
public int? MinSegments { get; set; }
public bool BreakOnNonKeyFrames { get; set; }
public bool RequireAvc { get; set; }
- public bool DeInterlace { get; set; }
public bool RequireNonAnamorphic { get; set; }
public bool CopyTimestamps { get; set; }
public bool EnableSubtitlesInManifest { get; set; }
@@ -62,13 +86,10 @@ namespace MediaBrowser.Model.Dlna
public int? VideoBitrate { get; set; }
- public int? VideoLevel { get; set; }
-
public int? MaxWidth { get; set; }
public int? MaxHeight { get; set; }
public int? MaxVideoBitDepth { get; set; }
- public int? MaxRefFrames { get; set; }
public float? MaxFramerate { get; set; }
@@ -92,6 +113,8 @@ namespace MediaBrowser.Model.Dlna
public List<MediaSourceInfo> AllMediaSources { get; set; }
public List<TranscodeReason> TranscodeReasons { get; set; }
+ public Dictionary<string, string> StreamOptions { get; private set; }
+
public string MediaSourceId
{
get
@@ -146,7 +169,9 @@ namespace MediaBrowser.Model.Dlna
continue;
}
- list.Add(string.Format("{0}={1}", pair.Name, pair.Value));
+ var encodedValue = pair.Value.Replace(" ", "%20");
+
+ list.Add(string.Format("{0}={1}", pair.Name, encodedValue));
}
string queryString = string.Join("&", list.ToArray(list.Count));
@@ -246,11 +271,37 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("StartTimeTicks", StringHelper.ToStringCultureInvariant(startPositionTicks)));
}
- list.Add(new NameValuePair("Level", item.VideoLevel.HasValue ? StringHelper.ToStringCultureInvariant(item.VideoLevel.Value) : string.Empty));
+ if (isDlna)
+ {
+ // hack alert
+ // dlna needs to be update to support the qualified params
+ var level = item.GetTargetVideoLevel("h264");
+
+ list.Add(new NameValuePair("Level", level.HasValue ? StringHelper.ToStringCultureInvariant(level.Value) : string.Empty));
+ }
+
+ if (isDlna)
+ {
+ // hack alert
+ // dlna needs to be update to support the qualified params
+ var refframes = item.GetTargetRefFrames("h264");
+
+ list.Add(new NameValuePair("MaxRefFrames", refframes.HasValue ? StringHelper.ToStringCultureInvariant(refframes.Value) : string.Empty));
+ }
- list.Add(new NameValuePair("MaxRefFrames", item.MaxRefFrames.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxRefFrames.Value) : string.Empty));
list.Add(new NameValuePair("MaxVideoBitDepth", item.MaxVideoBitDepth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxVideoBitDepth.Value) : string.Empty));
- list.Add(new NameValuePair("Profile", item.VideoProfile ?? string.Empty));
+
+ if (isDlna)
+ {
+ // hack alert
+ // dlna needs to be update to support the qualified params
+ var profile = item.GetOption("h264", "profile");
+
+ // Avoid having to encode
+ profile = (profile ?? string.Empty).Replace(" ", "");
+
+ list.Add(new NameValuePair("Profile", profile));
+ }
// no longer used
list.Add(new NameValuePair("Cabac", string.Empty));
@@ -282,7 +333,16 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("SubtitleCodec", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Embed ? subtitleCodecs : string.Empty));
list.Add(new NameValuePair("RequireNonAnamorphic", item.RequireNonAnamorphic.ToString().ToLower()));
- list.Add(new NameValuePair("DeInterlace", item.DeInterlace.ToString().ToLower()));
+
+ if (isDlna)
+ {
+ // hack alert
+ // dlna needs to be update to support the qualified params
+ var deinterlace = string.Equals(item.GetOption("h264", "deinterlace"), "true", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(item.GetOption("mpeg2video", "deinterlace"), "true", StringComparison.OrdinalIgnoreCase);
+
+ list.Add(new NameValuePair("DeInterlace", deinterlace.ToString().ToLower()));
+ }
if (!isDlna && isHls)
{
@@ -306,6 +366,20 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("TranscodeReasons", string.Join(",", item.TranscodeReasons.Distinct().Select(i => i.ToString()).ToArray())));
}
+ if (!isDlna)
+ {
+ foreach (var pair in item.StreamOptions)
+ {
+ if (string.IsNullOrWhiteSpace(pair.Value))
+ {
+ continue;
+ }
+
+ // strip spaces to avoid having to encode h264 profile names
+ list.Add(new NameValuePair(pair.Key, pair.Value.Replace(" ", "")));
+ }
+ }
+
return list;
}
@@ -509,8 +583,19 @@ namespace MediaBrowser.Model.Dlna
{
get
{
- MediaStream stream = TargetVideoStream;
- return stream == null || !IsDirectStream ? null : stream.RefFrames;
+ if (IsDirectStream)
+ {
+ return TargetVideoStream == null ? (int?)null : TargetVideoStream.RefFrames;
+ }
+
+ var targetVideoCodecs = TargetVideoCodec;
+ var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+ if (!string.IsNullOrWhiteSpace(videoCodec))
+ {
+ return GetTargetRefFrames(videoCodec);
+ }
+
+ return TargetVideoStream == null ? (int?)null : TargetVideoStream.RefFrames;
}
}
@@ -535,11 +620,54 @@ namespace MediaBrowser.Model.Dlna
{
get
{
- MediaStream stream = TargetVideoStream;
- return VideoLevel.HasValue && !IsDirectStream
- ? VideoLevel
- : stream == null ? null : stream.Level;
+ if (IsDirectStream)
+ {
+ return TargetVideoStream == null ? (double?)null : TargetVideoStream.Level;
+ }
+
+ var targetVideoCodecs = TargetVideoCodec;
+ var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+ if (!string.IsNullOrWhiteSpace(videoCodec))
+ {
+ return GetTargetVideoLevel(videoCodec);
+ }
+
+ return TargetVideoStream == null ? (double?)null : TargetVideoStream.Level;
+ }
+ }
+
+ public double? GetTargetVideoLevel(string codec)
+ {
+ var value = GetOption(codec, "level");
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return null;
+ }
+
+ double result;
+ if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+ {
+ return result;
}
+
+ return null;
+ }
+
+ public int? GetTargetRefFrames(string codec)
+ {
+ var value = GetOption(codec, "maxrefframes");
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return null;
+ }
+
+ int result;
+ if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
+ {
+ return result;
+ }
+
+ return null;
}
/// <summary>
@@ -563,10 +691,19 @@ namespace MediaBrowser.Model.Dlna
{
get
{
- MediaStream stream = TargetVideoStream;
- return !string.IsNullOrEmpty(VideoProfile) && !IsDirectStream
- ? VideoProfile
- : stream == null ? null : stream.Profile;
+ if (IsDirectStream)
+ {
+ return TargetVideoStream == null ? null : TargetVideoStream.Profile;
+ }
+
+ var targetVideoCodecs = TargetVideoCodec;
+ var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+ if (!string.IsNullOrWhiteSpace(videoCodec))
+ {
+ return GetOption(videoCodec, "profile");
+ }
+
+ return TargetVideoStream == null ? null : TargetVideoStream.Profile;
}
}
@@ -626,7 +763,7 @@ namespace MediaBrowser.Model.Dlna
/// <summary>
/// Predicts the audio codec that will be in the output stream
/// </summary>
- public string TargetAudioCodec
+ public string[] TargetAudioCodec
{
get
{
@@ -636,22 +773,22 @@ namespace MediaBrowser.Model.Dlna
if (IsDirectStream)
{
- return inputCodec;
+ return string.IsNullOrWhiteSpace(inputCodec) ? new string[] { } : new[] { inputCodec };
}
foreach (string codec in AudioCodecs)
{
if (StringHelper.EqualsIgnoreCase(codec, inputCodec))
{
- return codec;
+ return string.IsNullOrWhiteSpace(codec) ? new string[] { } : new[] { codec };
}
}
- return AudioCodecs.Length == 0 ? null : AudioCodecs[0];
+ return AudioCodecs;
}
}
- public string TargetVideoCodec
+ public string[] TargetVideoCodec
{
get
{
@@ -661,24 +798,24 @@ namespace MediaBrowser.Model.Dlna
if (IsDirectStream)
{
- return inputCodec;
+ return string.IsNullOrWhiteSpace(inputCodec) ? new string[] { } : new[] { inputCodec };
}
foreach (string codec in VideoCodecs)
{
if (StringHelper.EqualsIgnoreCase(codec, inputCodec))
{
- return codec;
+ return string.IsNullOrWhiteSpace(codec) ? new string[] { } : new[] { codec };
}
}
- return VideoCodecs.Length == 0 ? null : VideoCodecs[0];
+ return VideoCodecs;
}
}
-
+
/// <summary>
- /// Predicts the audio channels that will be in the output stream
- /// </summary>
+ /// Predicts the audio channels that will be in the output stream
+ /// </summary>
public long? TargetSize
{
get
@@ -763,9 +900,14 @@ namespace MediaBrowser.Model.Dlna
return TargetVideoStream == null ? (bool?)null : TargetVideoStream.IsInterlaced;
}
- if (DeInterlace)
+ var targetVideoCodecs = TargetVideoCodec;
+ var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+ if (!string.IsNullOrWhiteSpace(videoCodec))
{
- return false;
+ if (string.Equals(GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
}
return TargetVideoStream == null ? (bool?)null : TargetVideoStream.IsInterlaced;
diff --git a/MediaBrowser.Model/IO/IZipClient.cs b/MediaBrowser.Model/IO/IZipClient.cs
index ac57d58a6..2dc4880c2 100644
--- a/MediaBrowser.Model/IO/IZipClient.cs
+++ b/MediaBrowser.Model/IO/IZipClient.cs
@@ -23,6 +23,8 @@ namespace MediaBrowser.Model.IO
/// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
void ExtractAll(Stream source, string targetPath, bool overwriteExistingFiles);
+ void ExtractAllFromGz(Stream source, string targetPath, bool overwriteExistingFiles);
+
/// <summary>
/// Extracts all from zip.
/// </summary>
diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
index a6d4d4c33..00fd54271 100644
--- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs
+++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
@@ -204,9 +204,7 @@ namespace MediaBrowser.Providers.Manager
private bool HasImage(IHasMetadata item, ImageType type)
{
- var image = item.GetImageInfo(type, 0);
-
- return image != null;
+ return item.HasImage(type);
}
/// <summary>
diff --git a/MediaBrowser.Providers/TV/DummySeasonProvider.cs b/MediaBrowser.Providers/TV/DummySeasonProvider.cs
index 791d14b60..de51126ee 100644
--- a/MediaBrowser.Providers/TV/DummySeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/DummySeasonProvider.cs
@@ -113,7 +113,7 @@ namespace MediaBrowser.Providers.TV
CancellationToken cancellationToken)
{
var seasonName = seasonNumber == 0 ?
- _config.Configuration.SeasonZeroDisplayName :
+ _libraryManager.GetLibraryOptions(series).SeasonZeroDisplayName :
(seasonNumber.HasValue ? string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.Value.ToString(_usCulture)) : _localization.GetLocalizedString("NameSeasonUnknown"));
_logger.Info("Creating Season {0} entry for {1}", seasonName, series.Name);
diff --git a/MediaBrowser.Providers/TV/SeasonMetadataService.cs b/MediaBrowser.Providers/TV/SeasonMetadataService.cs
index 4e712d3e3..5e3dc3c62 100644
--- a/MediaBrowser.Providers/TV/SeasonMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeasonMetadataService.cs
@@ -8,9 +8,7 @@ using MediaBrowser.Providers.Manager;
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
namespace MediaBrowser.Providers.TV
@@ -23,9 +21,11 @@ namespace MediaBrowser.Providers.TV
if (item.IndexNumber.HasValue && item.IndexNumber.Value == 0)
{
- if (!string.Equals(item.Name, ServerConfigurationManager.Configuration.SeasonZeroDisplayName, StringComparison.OrdinalIgnoreCase))
+ var seasonZeroDisplayName = LibraryManager.GetLibraryOptions(item).SeasonZeroDisplayName;
+
+ if (!string.Equals(item.Name, seasonZeroDisplayName, StringComparison.OrdinalIgnoreCase))
{
- item.Name = ServerConfigurationManager.Configuration.SeasonZeroDisplayName;
+ item.Name = seasonZeroDisplayName;
updateType = updateType | ItemUpdateType.MetadataEdit;
}
}
diff --git a/MediaBrowser.Server.Mono/ImageEncoderHelper.cs b/MediaBrowser.Server.Mono/ImageEncoderHelper.cs
index 36f11a52b..5112c64ed 100644
--- a/MediaBrowser.Server.Mono/ImageEncoderHelper.cs
+++ b/MediaBrowser.Server.Mono/ImageEncoderHelper.cs
@@ -1,7 +1,6 @@
using System;
using Emby.Drawing;
using Emby.Drawing.ImageMagick;
-using Emby.Server.Core;
using Emby.Server.Implementations;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Net;
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index d2ce0b40d..365977530 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -55,9 +55,8 @@
<HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
<Private>True</Private>
</Reference>
- <Reference Include="SharpCompress, Version=0.14.0.0, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\SharpCompress.0.14.0\lib\net45\SharpCompress.dll</HintPath>
- <Private>True</Private>
+ <Reference Include="SharpCompress, Version=0.18.2.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
+ <HintPath>..\packages\SharpCompress.0.18.2\lib\net45\SharpCompress.dll</HintPath>
</Reference>
<Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
diff --git a/MediaBrowser.Server.Mono/MonoAppHost.cs b/MediaBrowser.Server.Mono/MonoAppHost.cs
index ded7bb5f3..c94334e89 100644
--- a/MediaBrowser.Server.Mono/MonoAppHost.cs
+++ b/MediaBrowser.Server.Mono/MonoAppHost.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Reflection;
using Emby.Server.CinemaMode;
using Emby.Server.Connect;
-using Emby.Server.Core;
using Emby.Server.Implementations;
using Emby.Server.Sync;
using MediaBrowser.Controller.Connect;
@@ -26,7 +25,7 @@ namespace MediaBrowser.Server.Mono
get
{
// A restart script must be provided
- return StartupOptions.ContainsOption("-restartpath");
+ return StartupOptions.ContainsOption("-restartpath") && StartupOptions.ContainsOption("-ffmpeg");
}
}
diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs
index 566a84da2..3267a77b9 100644
--- a/MediaBrowser.Server.Mono/Program.cs
+++ b/MediaBrowser.Server.Mono/Program.cs
@@ -12,8 +12,6 @@ using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Emby.Drawing;
-using Emby.Server.Core.Cryptography;
-using Emby.Server.Core;
using Emby.Server.Implementations;
using Emby.Server.Implementations.EnvironmentInfo;
using Emby.Server.Implementations.IO;
diff --git a/MediaBrowser.Server.Mono/packages.config b/MediaBrowser.Server.Mono/packages.config
index cff873f1f..dfa3dc75d 100644
--- a/MediaBrowser.Server.Mono/packages.config
+++ b/MediaBrowser.Server.Mono/packages.config
@@ -2,7 +2,7 @@
<packages>
<package id="Mono.Posix" version="4.0.0.0" targetFramework="net45" />
<package id="ServiceStack.Text" version="4.5.8" targetFramework="net46" />
- <package id="SharpCompress" version="0.14.0" targetFramework="net46" />
+ <package id="SharpCompress" version="0.18.2" targetFramework="net46" />
<package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
<package id="SkiaSharp" version="1.58.1" targetFramework="net46" />
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net46" />
diff --git a/MediaBrowser.ServerApplication/ImageEncoderHelper.cs b/MediaBrowser.ServerApplication/ImageEncoderHelper.cs
index 0e99bbbad..c86e85785 100644
--- a/MediaBrowser.ServerApplication/ImageEncoderHelper.cs
+++ b/MediaBrowser.ServerApplication/ImageEncoderHelper.cs
@@ -1,7 +1,6 @@
using System;
using Emby.Drawing;
using Emby.Drawing.Skia;
-using Emby.Server.Core;
using Emby.Server.Implementations;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Net;
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index d17d9ee43..70b03aa44 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -16,9 +16,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
-using Emby.Server.Core.Cryptography;
using Emby.Drawing;
-using Emby.Server.Core;
using Emby.Server.Implementations;
using Emby.Server.Implementations.Browser;
using Emby.Server.Implementations.EnvironmentInfo;
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 23db82cf1..9e4f52489 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -77,9 +77,8 @@
<HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
<Private>True</Private>
</Reference>
- <Reference Include="SharpCompress, Version=0.14.0.0, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\SharpCompress.0.14.0\lib\net45\SharpCompress.dll</HintPath>
- <Private>True</Private>
+ <Reference Include="SharpCompress, Version=0.18.2.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
+ <HintPath>..\packages\SharpCompress.0.18.2\lib\net45\SharpCompress.dll</HintPath>
</Reference>
<Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
diff --git a/MediaBrowser.ServerApplication/WindowsAppHost.cs b/MediaBrowser.ServerApplication/WindowsAppHost.cs
index 19079fbc9..9896b75e3 100644
--- a/MediaBrowser.ServerApplication/WindowsAppHost.cs
+++ b/MediaBrowser.ServerApplication/WindowsAppHost.cs
@@ -6,7 +6,6 @@ using System.Reflection;
using System.Runtime.InteropServices.ComTypes;
using Emby.Server.CinemaMode;
using Emby.Server.Connect;
-using Emby.Server.Core;
using Emby.Server.Implementations;
using Emby.Server.Implementations.EntryPoints;
using Emby.Server.Implementations.FFMpeg;
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index 85d2613bb..c7b98700e 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ServiceStack.Text" version="4.5.8" targetFramework="net462" />
- <package id="SharpCompress" version="0.14.0" targetFramework="net462" />
+ <package id="SharpCompress" version="0.18.2" targetFramework="net462" />
<package id="SimpleInjector" version="4.0.8" targetFramework="net462" />
<package id="SkiaSharp" version="1.58.1" targetFramework="net462" />
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net462" />