| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- using Admin.NET.Plugin.AiDOP.Entity.S8;
- using Admin.NET.Plugin.AiDOP.Infrastructure;
- using System.Text.RegularExpressions;
- namespace Admin.NET.Plugin.AiDOP.Service.S8;
- public class S8DataSourceService : ITransient
- {
- private readonly SqlSugarRepository<AdoS8DataSource> _rep;
- public S8DataSourceService(SqlSugarRepository<AdoS8DataSource> rep) => _rep = rep;
- public async Task<List<AdoS8DataSource>> ListAsync(long tenantId, long factoryId)
- {
- var rows = await _rep.AsQueryable()
- .Where(x => x.TenantId == tenantId && x.FactoryId == factoryId)
- .ToListAsync();
- foreach (var r in rows) r.Endpoint = MaskSecret(r.Endpoint);
- return rows;
- }
- // S8-TENANT-FACTORY-P0-CLOSURE-1:归属一律由服务端可信作用域盖章,忽略 body.TenantId / body.FactoryId。
- public async Task<AdoS8DataSource> CreateAsync(AdoS8DataSource body, S8TrustedScope scope)
- {
- if (string.IsNullOrWhiteSpace(body.DataSourceCode) || string.IsNullOrWhiteSpace(body.Type))
- throw new S8BizException("数据源编码和类型必填");
- body.TenantId = scope.TenantId;
- body.FactoryId = scope.FactoryId;
- var exists = await _rep.AsQueryable()
- .AnyAsync(x => x.TenantId == body.TenantId && x.FactoryId == body.FactoryId && x.DataSourceCode == body.DataSourceCode);
- if (exists) throw new S8BizException("数据源编码已存在");
- body.Id = 0;
- body.CreatedAt = DateTime.Now;
- await _rep.InsertAsync(body);
- body.Endpoint = MaskSecret(body.Endpoint);
- return body;
- }
- // S8-TENANT-FACTORY-P0-CLOSURE-1:按 Id + 可信作用域绑行;越权 Id 视为不存在,归属不可被 body 改写。
- public async Task<AdoS8DataSource> UpdateAsync(long id, AdoS8DataSource body, S8TrustedScope scope)
- {
- var e = await LoadScopedAsync(id, scope);
- if (string.IsNullOrWhiteSpace(body.DataSourceCode) || string.IsNullOrWhiteSpace(body.Type))
- throw new S8BizException("数据源编码和类型必填");
- var exists = await _rep.AsQueryable()
- .AnyAsync(x => x.Id != id && x.TenantId == e.TenantId && x.FactoryId == e.FactoryId && x.DataSourceCode == body.DataSourceCode);
- if (exists) throw new S8BizException("数据源编码已存在");
- // 入参 endpoint 含掩码占位符(Pwd=****** / Password=******)时保留旧值的真实密码段,避免前端
- // 回填脱敏值后误覆盖。Endpoint 全空时也不覆盖原密码。
- body.Endpoint = MergeEndpointPreservingSecret(body.Endpoint, e.Endpoint);
- body.Id = id;
- body.TenantId = e.TenantId;
- body.FactoryId = e.FactoryId;
- body.CreatedAt = e.CreatedAt;
- body.UpdatedAt = DateTime.Now;
- await _rep.UpdateAsync(body);
- body.Endpoint = MaskSecret(body.Endpoint);
- return body;
- }
- // S8-TENANT-FACTORY-P0-CLOSURE-1:删除必须先按可信作用域绑行,禁止裸 DeleteByIdAsync(id)。
- public async Task DeleteAsync(long id, S8TrustedScope scope)
- {
- var e = await LoadScopedAsync(id, scope);
- await _rep.DeleteByIdAsync(e.Id);
- }
- /// <summary>按 Id + 可信作用域取行;不在作用域内一律按「不存在」处理,不泄露他租户资源是否存在。</summary>
- private async Task<AdoS8DataSource> LoadScopedAsync(long id, S8TrustedScope scope) =>
- await _rep.AsQueryable()
- .Where(x => x.Id == id && x.TenantId == scope.TenantId && x.FactoryId == scope.FactoryId)
- .FirstAsync() ?? throw new S8NotFoundException();
- public async Task<object> TestAsync(long id, S8TrustedScope scope)
- {
- var entity = await LoadScopedAsync(id, scope);
- var success = !string.IsNullOrWhiteSpace(entity.Endpoint);
- entity.LastCheckAt = DateTime.Now;
- entity.LastCheckStatus = success ? "SUCCESS" : "FAILED: endpoint is empty";
- entity.UpdatedAt = DateTime.Now;
- await _rep.UpdateAsync(entity);
- return new
- {
- id,
- success,
- message = success ? "连接信息校验通过" : "连接地址为空,未通过校验",
- entity.LastCheckAt,
- entity.LastCheckStatus
- };
- }
- // BUG-13:endpoint 中的 Pwd=xxx / Password=xxx(大小写不敏感)替换为 ******,保留其它字段。
- private static readonly Regex SecretPattern = new(
- @"(?i)(Pwd|Password)\s*=\s*([^;]*)",
- RegexOptions.Compiled);
- private static string? MaskSecret(string? endpoint)
- {
- if (string.IsNullOrWhiteSpace(endpoint)) return endpoint;
- return SecretPattern.Replace(endpoint, m => $"{m.Groups[1].Value}=******");
- }
- private static string? MergeEndpointPreservingSecret(string? incoming, string? existing)
- {
- if (string.IsNullOrWhiteSpace(incoming)) return existing;
- if (string.IsNullOrWhiteSpace(existing)) return incoming;
- // 提取旧 endpoint 中的真实密码值(首个匹配为准)
- var oldMatch = SecretPattern.Match(existing);
- if (!oldMatch.Success) return incoming;
- var realSecret = oldMatch.Groups[2].Value;
- // 把入参里 Pwd=****** 之类的占位还原为真实密码
- return SecretPattern.Replace(incoming, m =>
- {
- var v = m.Groups[2].Value;
- return IsMaskedPlaceholder(v) ? $"{m.Groups[1].Value}={realSecret}" : m.Value;
- });
- }
- private static bool IsMaskedPlaceholder(string? v) =>
- !string.IsNullOrEmpty(v) && v.All(c => c == '*');
- }
|