diff options
| -rw-r--r-- | .ci/publish-nightly.yml | 46 | ||||
| -rw-r--r-- | .ci/publish-release.yml | 48 | ||||
| -rw-r--r-- | CONTRIBUTORS.md | 1 | ||||
| -rw-r--r-- | Dockerfile | 17 | ||||
| -rw-r--r-- | Dockerfile.arm | 16 | ||||
| -rw-r--r-- | Dockerfile.arm64 | 16 | ||||
| -rw-r--r-- | Emby.Server.Implementations/Library/UserManager.cs | 47 | ||||
| -rw-r--r-- | Jellyfin.Drawing.Skia/SkiaCodecException.cs | 46 | ||||
| -rw-r--r-- | Jellyfin.Drawing.Skia/SkiaEncoder.cs | 12 | ||||
| -rw-r--r-- | Jellyfin.Drawing.Skia/SkiaException.cs | 26 | ||||
| -rw-r--r-- | Jellyfin.Drawing.Skia/SkiaHelper.cs | 23 | ||||
| -rw-r--r-- | MediaBrowser.Model/Users/UserPolicy.cs | 2 |
12 files changed, 251 insertions, 49 deletions
diff --git a/.ci/publish-nightly.yml b/.ci/publish-nightly.yml new file mode 100644 index 000000000..a693e10f6 --- /dev/null +++ b/.ci/publish-nightly.yml @@ -0,0 +1,46 @@ +name: Nightly-$(date:yyyyMMdd).$(rev:r) + +variables: + - name: Version + value: '1.0.0' + +trigger: none +pr: none + +jobs: + - job: publish_artifacts_nightly + displayName: Publish Artifacts Nightly + pool: + vmImage: ubuntu-latest + steps: + - checkout: none + - task: DownloadPipelineArtifact@2 + displayName: Download the Windows Setup Artifact + inputs: + source: 'specific' # Options: current, specific + artifact: 'Jellyfin Server Setup' # Optional + path: '$(System.ArtifactsDirectory)/win-installer' + project: '$(System.TeamProjectId)' # Required when source == Specific + pipelineId: 1 # Required when source == Specific + runVersion: 'latestFromBranch' # Required when source == Specific. Options: latest, latestFromBranch, specific + runBranch: 'refs/heads/master' # Required when source == Specific && runVersion == LatestFromBranch + + - task: SSH@0 + displayName: 'Create Drop directory' + inputs: + sshEndpoint: 'Jellyfin Build Server' + commands: 'mkdir -p /srv/incoming/jellyfin_$(Version)/win-installer && ln -s /srv/incoming/jellyfin_$(Version) /srv/incoming/jellyfin_nightly_azure_upload' + + - task: CopyFilesOverSSH@0 + displayName: 'Copy the Windows Setup to the Repo' + inputs: + sshEndpoint: 'Jellyfin Build Server' + sourceFolder: '$(System.ArtifactsDirectory)/win-installer' + contents: 'jellyfin_*.exe' + targetFolder: '/srv/incoming/jellyfin_nightly_azure_upload/win-installer' + + - task: SSH@0 + displayName: 'Clean up SCP symlink' + inputs: + sshEndpoint: 'Jellyfin Build Server' + commands: 'rm -f /srv/incoming/jellyfin_nightly_azure_upload' diff --git a/.ci/publish-release.yml b/.ci/publish-release.yml new file mode 100644 index 000000000..57e77ae5a --- /dev/null +++ b/.ci/publish-release.yml @@ -0,0 +1,48 @@ +name: Release-$(Version)-$(date:yyyyMMdd).$(rev:r) + +variables: + - name: Version + value: '1.0.0' + - name: UsedRunId + value: 0 + +trigger: none +pr: none + +jobs: + - job: publish_artifacts_release + displayName: Publish Artifacts Release + pool: + vmImage: ubuntu-latest + steps: + - checkout: none + - task: DownloadPipelineArtifact@2 + displayName: Download the Windows Setup Artifact + inputs: + source: 'specific' # Options: current, specific + artifact: 'Jellyfin Server Setup' # Optional + path: '$(System.ArtifactsDirectory)/win-installer' + project: '$(System.TeamProjectId)' # Required when source == Specific + pipelineId: 1 # Required when source == Specific + runVersion: 'specific' # Required when source == Specific. Options: latest, latestFromBranch, specific + runId: $(UsedRunId) + + - task: SSH@0 + displayName: 'Create Drop directory' + inputs: + sshEndpoint: 'Jellyfin Build Server' + commands: 'mkdir -p /srv/incoming/jellyfin_$(Version)/win-installer && ln -s /srv/incoming/jellyfin_$(Version) /srv/incoming/jellyfin_release_azure_upload' + + - task: CopyFilesOverSSH@0 + displayName: 'Copy the Windows Setup to the Repo' + inputs: + sshEndpoint: 'Jellyfin Build Server' + sourceFolder: '$(System.ArtifactsDirectory)/win-installer' + contents: 'jellyfin_*.exe' + targetFolder: '/srv/incoming/jellyfin_release_azure_upload/win-installer' + + - task: SSH@0 + displayName: 'Clean up SCP symlink' + inputs: + sshEndpoint: 'Jellyfin Build Server' + commands: 'rm -f /srv/incoming/jellyfin_release_azure_upload' diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index c95133dfd..f22944a8b 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -29,6 +29,7 @@ - [joern-h](https://github.com/joern-h) - [Khinenw](https://github.com/HelloWorld017) - [fhriley](https://github.com/fhriley) + - [nevado](https://github.com/nevado) # Emby Contributors diff --git a/Dockerfile b/Dockerfile index ec64398b2..017f8c697 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,15 @@ ARG DOTNET_VERSION=2.2 ARG FFMPEG_VERSION=latest +FROM node:alpine as web-builder +ARG JELLYFIN_WEB_VERSION=v10.4.0 +RUN apk add curl \ + && curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \ + && cd jellyfin-web-* \ + && yarn install \ + && yarn build \ + && mv dist /dist + FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder WORKDIR /repo COPY . . @@ -13,7 +22,7 @@ FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION} # libfontconfig1 is required for Skia RUN apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y \ - libfontconfig1 \ + libfontconfig1 mesa-va-drivers \ && apt-get clean autoclean \ && apt-get autoremove \ && rm -rf /var/lib/apt/lists/* \ @@ -21,11 +30,7 @@ RUN apt-get update \ && chmod 777 /cache /config /media COPY --from=ffmpeg / / COPY --from=builder /jellyfin /jellyfin - -ARG JELLYFIN_WEB_VERSION=v10.4.0 -RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \ - && rm -rf /jellyfin/jellyfin-web \ - && mv jellyfin-web-* /jellyfin/jellyfin-web +COPY --from=web-builder /dist /jellyfin/jellyfin-web/src EXPOSE 8096 VOLUME /cache /config /media diff --git a/Dockerfile.arm b/Dockerfile.arm index 2b1c6bb62..d06eeb561 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -3,6 +3,16 @@ ARG DOTNET_VERSION=3.0 +FROM node:alpine as web-builder +ARG JELLYFIN_WEB_VERSION=v10.4.0 +RUN apk add curl \ + && curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \ + && cd jellyfin-web-* \ + && yarn install \ + && yarn build \ + && mv dist /dist + + FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder WORKDIR /repo COPY . . @@ -25,11 +35,7 @@ RUN apt-get update \ && mkdir -p /cache /config /media \ && chmod 777 /cache /config /media COPY --from=builder /jellyfin /jellyfin - -ARG JELLYFIN_WEB_VERSION=v10.4.0 -RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \ - && rm -rf /jellyfin/jellyfin-web \ - && mv jellyfin-web-* /jellyfin/jellyfin-web +COPY --from=web-builder /dist /jellyfin/jellyfin-web/src EXPOSE 8096 VOLUME /cache /config /media diff --git a/Dockerfile.arm64 b/Dockerfile.arm64 index 5ebc82ebc..1c5de4ed0 100644 --- a/Dockerfile.arm64 +++ b/Dockerfile.arm64 @@ -3,6 +3,16 @@ ARG DOTNET_VERSION=3.0 +FROM node:alpine as web-builder +ARG JELLYFIN_WEB_VERSION=v10.4.0 +RUN apk add curl \ + && curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \ + && cd jellyfin-web-* \ + && yarn install \ + && yarn build \ + && mv dist /dist + + FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder WORKDIR /repo COPY . . @@ -25,11 +35,7 @@ RUN apt-get update \ && mkdir -p /cache /config /media \ && chmod 777 /cache /config /media COPY --from=builder /jellyfin /jellyfin - -ARG JELLYFIN_WEB_VERSION=v10.4.0 -RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \ - && rm -rf /jellyfin/jellyfin-web \ - && mv jellyfin-web-* /jellyfin/jellyfin-web +COPY --from=web-builder /dist /jellyfin/jellyfin-web/src EXPOSE 8096 VOLUME /cache /config /media diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index a7ea13ca6..afa53ff37 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -353,11 +353,11 @@ namespace Emby.Server.Implementations.Library UpdateUser(user); } - UpdateInvalidLoginAttemptCount(user, 0); + ResetInvalidLoginAttemptCount(user); } else { - UpdateInvalidLoginAttemptCount(user, user.Policy.InvalidLoginAttemptCount + 1); + IncrementInvalidLoginAttemptCount(user); } _logger.LogInformation("Authentication request for {0} {1}.", user.Name, success ? "has succeeded" : "has been denied"); @@ -509,41 +509,28 @@ namespace Emby.Server.Implementations.Library : PasswordHash.ConvertToByteString(new PasswordHash(user.EasyPassword).Hash); } - private void UpdateInvalidLoginAttemptCount(User user, int newValue) + private void ResetInvalidLoginAttemptCount(User user) { - if (user.Policy.InvalidLoginAttemptCount == newValue || newValue <= 0) - { - return; - } - - user.Policy.InvalidLoginAttemptCount = newValue; - - // Check for users without a value here and then fill in the default value - // also protect from an always lockout if misconfigured - if (user.Policy.LoginAttemptsBeforeLockout == null || user.Policy.LoginAttemptsBeforeLockout == 0) - { - user.Policy.LoginAttemptsBeforeLockout = user.Policy.IsAdministrator ? 5 : 3; - } - - var maxCount = user.Policy.LoginAttemptsBeforeLockout; - - var fireLockout = false; + user.Policy.InvalidLoginAttemptCount = 0; + UpdateUserPolicy(user, user.Policy, false); + } - // -1 can be used to specify no lockout value - if (maxCount != -1 && newValue >= maxCount) + private void IncrementInvalidLoginAttemptCount(User user) + { + int invalidLogins = ++user.Policy.InvalidLoginAttemptCount; + int maxInvalidLogins = user.Policy.LoginAttemptsBeforeLockout; + if (maxInvalidLogins > 0 + && invalidLogins >= maxInvalidLogins) { - _logger.LogDebug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue); user.Policy.IsDisabled = true; - - fireLockout = true; + UserLockedOut?.Invoke(this, new GenericEventArgs<User>(user)); + _logger.LogWarning( + "Disabling user {UserName} due to {Attempts} unsuccessful login attempts.", + user.Name, + invalidLogins); } UpdateUserPolicy(user, user.Policy, false); - - if (fireLockout) - { - UserLockedOut?.Invoke(this, new GenericEventArgs<User>(user)); - } } /// <summary> diff --git a/Jellyfin.Drawing.Skia/SkiaCodecException.cs b/Jellyfin.Drawing.Skia/SkiaCodecException.cs new file mode 100644 index 000000000..f848636bc --- /dev/null +++ b/Jellyfin.Drawing.Skia/SkiaCodecException.cs @@ -0,0 +1,46 @@ +using System.Globalization; +using SkiaSharp; + +namespace Jellyfin.Drawing.Skia +{ + /// <summary> + /// Represents errors that occur during interaction with Skia codecs. + /// </summary> + public class SkiaCodecException : SkiaException + { + /// <summary> + /// Returns the non-successfull codec result returned by Skia. + /// </summary> + /// <value>The non-successfull codec result returned by Skia.</value> + public SKCodecResult CodecResult { get; } + + /// <summary> + /// Initializes a new instance of the <see cref="SkiaCodecException" /> class. + /// </summary> + /// <param name="result">The non-successfull codec result returned by Skia.</param> + public SkiaCodecException(SKCodecResult result) : base() + { + CodecResult = result; + } + + /// <summary> + /// Initializes a new instance of the <see cref="SkiaCodecException" /> class + /// with a specified error message. + /// </summary> + /// <param name="result">The non-successfull codec result returned by Skia.</param> + /// <param name="message">The message that describes the error.</param> + public SkiaCodecException(SKCodecResult result, string message) + : base(message) + { + CodecResult = result; + } + + /// <inheritdoc /> + public override string ToString() + => string.Format( + CultureInfo.InvariantCulture, + "Non-success codec result: {0}\n{1}", + CodecResult, + base.ToString()); + } +} diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs index 80b9974fa..66b814f6e 100644 --- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -9,6 +9,7 @@ using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Globalization; using Microsoft.Extensions.Logging; using SkiaSharp; +using static Jellyfin.Drawing.Skia.SkiaHelper; namespace Jellyfin.Drawing.Skia { @@ -184,16 +185,23 @@ namespace Jellyfin.Drawing.Skia } } + /// <inheritdoc /> public ImageDimensions GetImageSize(string path) { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + if (!File.Exists(path)) { throw new FileNotFoundException("File not found", path); } - using (var s = new SKFileStream(path)) - using (var codec = SKCodec.Create(s)) + using (var codec = SKCodec.Create(path, out SKCodecResult result)) { + EnsureSuccess(result); + var info = codec.Info; return new ImageDimensions(info.Width, info.Height); diff --git a/Jellyfin.Drawing.Skia/SkiaException.cs b/Jellyfin.Drawing.Skia/SkiaException.cs new file mode 100644 index 000000000..7aeaf083e --- /dev/null +++ b/Jellyfin.Drawing.Skia/SkiaException.cs @@ -0,0 +1,26 @@ +using System; + +namespace Jellyfin.Drawing.Skia +{ + /// <summary> + /// Represents errors that occur during interaction with Skia. + /// </summary> + public class SkiaException : Exception + { + /// <inheritdoc /> + public SkiaException() : base() + { + } + + /// <inheritdoc /> + public SkiaException(string message) : base(message) + { + } + + /// <inheritdoc /> + public SkiaException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/Jellyfin.Drawing.Skia/SkiaHelper.cs b/Jellyfin.Drawing.Skia/SkiaHelper.cs new file mode 100644 index 000000000..f9c79c855 --- /dev/null +++ b/Jellyfin.Drawing.Skia/SkiaHelper.cs @@ -0,0 +1,23 @@ +using SkiaSharp; + +namespace Jellyfin.Drawing.Skia +{ + /// <summary> + /// Class containing helper methods for working with SkiaSharp. + /// </summary> + public static class SkiaHelper + { + /// <summary> + /// Ensures the result is a success + /// by throwing an exception when that's not the case. + /// </summary> + /// <param name="result">The result returned by Skia.</param> + public static void EnsureSuccess(SKCodecResult result) + { + if (result != SKCodecResult.Success) + { + throw new SkiaCodecException(result); + } + } + } +} diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index f63ab2bb4..9336c720f 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -66,7 +66,7 @@ namespace MediaBrowser.Model.Users public bool EnableAllFolders { get; set; } public int InvalidLoginAttemptCount { get; set; } - public int? LoginAttemptsBeforeLockout { get; set; } + public int LoginAttemptsBeforeLockout { get; set; } public bool EnablePublicSharing { get; set; } |
