update:阿里云下载
This commit is contained in:
parent
0afa0f8c1a
commit
2fa9d1e29d
@ -1,6 +1,8 @@
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.Extensions.Options;
|
||||
using YD_Event.Application.Auth;
|
||||
using YD_Event.Application.Common;
|
||||
using YD_Event.Core.Options;
|
||||
|
||||
namespace YD_Event.Application.AppUpdate;
|
||||
|
||||
@ -16,15 +18,18 @@ public class AppUpdateController : IDynamicApiController
|
||||
private readonly AuthManager _auth;
|
||||
private readonly IIdGenerator _ids;
|
||||
private readonly FileService _files;
|
||||
private readonly IOptionsMonitor<OssConnectionOptions> _ossOptions;
|
||||
private readonly string _channel;
|
||||
|
||||
public AppUpdateController(ISqlSugarRepository<JudgeAppRelease> releases,
|
||||
AuthManager auth, IIdGenerator ids, FileService files)
|
||||
AuthManager auth, IIdGenerator ids, FileService files,
|
||||
IOptionsMonitor<OssConnectionOptions> ossOptions)
|
||||
{
|
||||
_releases = releases;
|
||||
_auth = auth;
|
||||
_ids = ids;
|
||||
_files = files;
|
||||
_ossOptions = ossOptions;
|
||||
_channel = Environment.GetEnvironmentVariable("APP_UPDATE_CHANNEL")?.Trim().ToLowerInvariant() ?? "production";
|
||||
}
|
||||
|
||||
@ -41,11 +46,43 @@ public class AppUpdateController : IDynamicApiController
|
||||
available = true, release.Id, release.PackageName, release.VersionCode,
|
||||
release.VersionName, release.NotesZh, release.NotesEn,
|
||||
release.IsMandatory, release.FileSize, release.Sha256,
|
||||
release.CertificateSha256, downloadUrl = $"/api/app-updates/download/{release.Id}",
|
||||
release.CertificateSha256, downloadUrl = DownloadUrlFor(release),
|
||||
release.PublishedTime
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>OSS 已启用时直连阿里云/CDN;配置缺失或不安全时仍使用受控下载接口。</summary>
|
||||
private string DownloadUrlFor(JudgeAppRelease release)
|
||||
{
|
||||
var fallback = $"/api/app-updates/download/{release.Id}";
|
||||
// Direct delivery is opt-in: a private bucket without CDN/public-read
|
||||
// must continue using the existing server-side OSS stream.
|
||||
var cdn = Environment.GetEnvironmentVariable("APP_UPDATE_DIRECT_DOWNLOAD_BASE_URL");
|
||||
if (string.IsNullOrWhiteSpace(cdn)) return fallback;
|
||||
var oss = _ossOptions.CurrentValue;
|
||||
if (!oss.Enable || string.IsNullOrWhiteSpace(oss.Domain) ||
|
||||
!Uri.TryCreate(oss.Domain.TrimEnd('/') + "/", UriKind.Absolute, out var ossBase) ||
|
||||
ossBase.Scheme != Uri.UriSchemeHttps ||
|
||||
!Uri.TryCreate(release.FileUrl, UriKind.Absolute, out var fileUri) ||
|
||||
fileUri.Scheme != Uri.UriSchemeHttps ||
|
||||
!fileUri.AbsoluteUri.StartsWith(ossBase.AbsoluteUri, StringComparison.OrdinalIgnoreCase))
|
||||
return fallback;
|
||||
|
||||
// FileUrl comes from the configured OSS domain at upload time. Never turn
|
||||
// an arbitrary stored URL into an untrusted redirect/download host.
|
||||
var objectKey = fileUri.AbsoluteUri[ossBase.AbsoluteUri.Length..];
|
||||
if (!objectKey.StartsWith($"app-releases/{_channel}/", StringComparison.Ordinal) ||
|
||||
objectKey.Contains("..", StringComparison.Ordinal) ||
|
||||
!objectKey.EndsWith(".apk", StringComparison.OrdinalIgnoreCase))
|
||||
return fallback;
|
||||
|
||||
if (!Uri.TryCreate(cdn.TrimEnd('/') + "/", UriKind.Absolute, out var cdnBase) ||
|
||||
cdnBase.Scheme != Uri.UriSchemeHttps || !string.IsNullOrEmpty(cdnBase.UserInfo) ||
|
||||
!string.IsNullOrEmpty(cdnBase.Query) || !string.IsNullOrEmpty(cdnBase.Fragment))
|
||||
return fallback;
|
||||
return new Uri(cdnBase, objectKey).AbsoluteUri;
|
||||
}
|
||||
|
||||
/// <summary>只允许下载当前环境已发布的版本,沿用现有文件服务流式返回。</summary>
|
||||
[HttpGet("download/{id:long}")]
|
||||
[AllowAnonymous]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user