修复相关漏洞
This commit is contained in:
+109
-17
@@ -48,6 +48,12 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
/// <inheritdoc />
|
||||
public async Task<OnboardingElectronicSignDetailOutput> Initiate(
|
||||
OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
return await OnboardingConcurrency.RunTask(_db, input.TaskId, () => InitiateCore(input));
|
||||
}
|
||||
|
||||
private async Task<OnboardingElectronicSignDetailOutput> InitiateCore(
|
||||
OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
var task = await GetAuthorizedTask(input.TaskId);
|
||||
ValidateTaskCanSign(task);
|
||||
@@ -99,6 +105,12 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
/// <inheritdoc />
|
||||
public async Task<OnboardingElectronicSignDetailOutput> Reinitiate(
|
||||
OnboardingElectronicSignReinitiateInput input)
|
||||
{
|
||||
return await OnboardingConcurrency.RunTask(_db, input.TaskId, () => ReinitiateCore(input));
|
||||
}
|
||||
|
||||
private async Task<OnboardingElectronicSignDetailOutput> ReinitiateCore(
|
||||
OnboardingElectronicSignReinitiateInput input)
|
||||
{
|
||||
var task = await GetAuthorizedTask(input.TaskId);
|
||||
ValidateTaskCanSign(task);
|
||||
@@ -256,6 +268,12 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
/// <inheritdoc />
|
||||
public async Task<OnboardingElectronicSignDetailOutput> Sync(
|
||||
OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
return await OnboardingConcurrency.RunTask(_db, input.TaskId, () => SyncCore(input));
|
||||
}
|
||||
|
||||
private async Task<OnboardingElectronicSignDetailOutput> SyncCore(
|
||||
OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
var task = await GetAuthorizedTask(input.TaskId);
|
||||
var process = await GetRequiredProcess(task.Id);
|
||||
@@ -266,6 +284,12 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
/// <inheritdoc />
|
||||
public async Task<OnboardingElectronicSignDetailOutput> GetSignLink(
|
||||
OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
return await OnboardingConcurrency.RunTask(_db, input.TaskId, () => GetSignLinkCore(input));
|
||||
}
|
||||
|
||||
private async Task<OnboardingElectronicSignDetailOutput> GetSignLinkCore(
|
||||
OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
var task = await GetAuthorizedTask(input.TaskId);
|
||||
var process = await GetRequiredProcess(task.Id);
|
||||
@@ -289,6 +313,12 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
/// <inheritdoc />
|
||||
public async Task<OnboardingElectronicSignPreviewOutput> PreviewEmployeeSignedDocument(
|
||||
OnboardingElectronicSignPreviewInput input)
|
||||
{
|
||||
return await OnboardingConcurrency.RunTask(_db, input.TaskId, () => PreviewEmployeeSignedDocumentCore(input));
|
||||
}
|
||||
|
||||
private async Task<OnboardingElectronicSignPreviewOutput> PreviewEmployeeSignedDocumentCore(
|
||||
OnboardingElectronicSignPreviewInput input)
|
||||
{
|
||||
var task = await GetTask(input.TaskId);
|
||||
var process = await GetRequiredProcess(task.Id);
|
||||
@@ -346,6 +376,12 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
/// <inheritdoc />
|
||||
public async Task<OnboardingElectronicSignDetailOutput> CompanySeal(
|
||||
OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
return await OnboardingConcurrency.RunTask(_db, input.TaskId, () => CompanySealCore(input));
|
||||
}
|
||||
|
||||
private async Task<OnboardingElectronicSignDetailOutput> CompanySealCore(
|
||||
OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
var task = await GetAuthorizedTask(input.TaskId);
|
||||
var process = await GetRequiredProcess(task.Id);
|
||||
@@ -378,7 +414,29 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
$"请先逐份查看员工已签文件:{string.Join("、", notPreviewed)}");
|
||||
}
|
||||
|
||||
// 发出前持久化占用。进程退出/响应丢失也不能自动重发可能已送达的盖章命令。
|
||||
var alreadySubmitted = await _db.Queryable<ObElectronicSignEvent>()
|
||||
.AnyAsync(item => item.SignProcessId == process.Id
|
||||
&& item.EventSource == AdminCompanySealEventSource
|
||||
&& (item.EventType == "company_seal_submitted"
|
||||
|| item.EventType == "company_seal_dispatch_started"));
|
||||
if (alreadySubmitted)
|
||||
throw Oops.Bah("企业盖章命令已发送或结果待确认,请先刷新签署状态并核实契约锁平台,系统不会重复盖章");
|
||||
|
||||
var companyName = await GetCompanyLegalName(task);
|
||||
await RecordAdminOperation(
|
||||
process,
|
||||
AdminCompanySealEventSource,
|
||||
"company_seal_dispatch_started",
|
||||
JsonSerializer.Serialize(new
|
||||
{
|
||||
process.ProviderContractId,
|
||||
companyName,
|
||||
process.SealId,
|
||||
operatorUserId = UserManager.UserId,
|
||||
operatorName = UserManager.Name
|
||||
}),
|
||||
"已占用盖章请求;发送结果待确认,禁止自动重复发送");
|
||||
try
|
||||
{
|
||||
await _qiyuesuoClient.CompanySign(
|
||||
@@ -406,10 +464,10 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
return await BuildDetail(task, process);
|
||||
}
|
||||
|
||||
process.LastError = $"企业盖章失败:{LimitError(signException.Message)}";
|
||||
process.LastError = $"企业盖章结果待核实,已阻止重复发送:{LimitError(signException.Message)}";
|
||||
process.UpdateTime = DateTime.Now;
|
||||
await _db.Updateable(process).ExecuteCommandAsync();
|
||||
throw;
|
||||
throw Oops.Bah("企业盖章未确认成功,请刷新状态并核实契约锁平台;为避免重复盖章,不能直接重发。原因:" + LimitError(signException.Message));
|
||||
}
|
||||
|
||||
await RecordAdminOperation(
|
||||
@@ -441,6 +499,11 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task Notice(OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
await OnboardingConcurrency.RunTask(_db, input.TaskId, () => NoticeCore(input));
|
||||
}
|
||||
|
||||
private async Task NoticeCore(OnboardingElectronicSignTaskInput input)
|
||||
{
|
||||
var task = await GetAuthorizedTask(input.TaskId);
|
||||
var process = await GetRequiredProcess(task.Id);
|
||||
@@ -455,6 +518,11 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task Invalid(OnboardingElectronicSignInvalidInput input)
|
||||
{
|
||||
await OnboardingConcurrency.RunTask(_db, input.TaskId, () => InvalidCore(input));
|
||||
}
|
||||
|
||||
private async Task InvalidCore(OnboardingElectronicSignInvalidInput input)
|
||||
{
|
||||
var task = await GetAuthorizedTask(input.TaskId);
|
||||
var process = await GetRequiredProcess(task.Id);
|
||||
@@ -478,6 +546,21 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task HandleCallback(string payloadJson)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(payloadJson))
|
||||
throw Oops.Bah("契约锁回调内容为空");
|
||||
using var json = JsonDocument.Parse(payloadJson);
|
||||
var process = await FindProcess(FindString(json.RootElement, "contractId"), FindString(json.RootElement, "bizId"));
|
||||
if (process == null)
|
||||
{
|
||||
await HandleCallbackCore(payloadJson);
|
||||
return;
|
||||
}
|
||||
// 只在锁外定位任务;锁内重新读取事件和流程,重复回调不会同时执行归档。
|
||||
await OnboardingConcurrency.RunTask(_db, process.TaskId, () => HandleCallbackCore(payloadJson, taskLockHeld: true));
|
||||
}
|
||||
|
||||
private async Task HandleCallbackCore(string payloadJson, bool taskLockHeld = false)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(payloadJson))
|
||||
throw Oops.Bah("契约锁回调内容为空");
|
||||
@@ -504,6 +587,13 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
"contractStatus",
|
||||
"status");
|
||||
var process = await FindProcess(providerContractId, bizId);
|
||||
// 回调首次定位时流程可能还在创建;若此刻才匹配到,先取得任务锁再重新执行。
|
||||
if (process != null && !taskLockHeld)
|
||||
{
|
||||
await OnboardingConcurrency.RunTask(_db, process.TaskId,
|
||||
() => HandleCallbackCore(payloadJson, taskLockHeld: true));
|
||||
return;
|
||||
}
|
||||
if (callbackEvent == null)
|
||||
{
|
||||
callbackEvent = new ObElectronicSignEvent
|
||||
@@ -549,7 +639,7 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
try
|
||||
{
|
||||
process.LastCallbackAt = DateTime.Now;
|
||||
await _db.Updateable(process).ExecuteCommandAsync();
|
||||
await _db.Updateable(process).UpdateColumns(item => item.LastCallbackAt).ExecuteCommandAsync();
|
||||
// 明文回调只作为刷新触发器,最终状态重新向契约锁查询,伪造回调不能改变业务状态。
|
||||
await SyncProcess(process, "callback");
|
||||
callbackEvent.ProviderStatus = process.ProviderStatus;
|
||||
@@ -939,7 +1029,7 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
ObElectronicSignProcess process,
|
||||
QiyuesuoContractResult providerContract)
|
||||
{
|
||||
var localStatus = ResolveSignStatus(providerContract);
|
||||
var localStatus = OnboardingSignStateGuard.Resolve(process.SignStatus, ResolveSignStatus(providerContract));
|
||||
process.ProviderStatus = providerContract.Status;
|
||||
process.SignStatus = localStatus;
|
||||
if (localStatus == ElectronicSignStatus.Completed
|
||||
@@ -950,7 +1040,8 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
process.SignUrlExpireAt = null;
|
||||
await _db.Updateable<ObTaskContract>()
|
||||
.SetColumns(item => item.ContractStatus == TaskContractStatus.ElectronicSigned)
|
||||
.Where(item => item.TaskId == process.TaskId)
|
||||
.Where(item => item.TaskId == process.TaskId && process.IsCurrent == true
|
||||
&& item.ContractStatus != TaskContractStatus.Archived)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
else if (IsTerminal(localStatus))
|
||||
@@ -974,24 +1065,25 @@ public class OnboardingElectronicSignService : IOnboardingElectronicSignService
|
||||
|
||||
foreach (var document in documents)
|
||||
{
|
||||
if (document.SignedPdfFileId.HasValue)
|
||||
continue;
|
||||
var signedPdf = await _qiyuesuoClient.DownloadDocument(
|
||||
document.ProviderDocumentId);
|
||||
var pdfFileId = await _fileService.StoreGeneratedFile(
|
||||
SysDictConst.FILE_ENGINE_ALIYUN_OSS,
|
||||
$"{SafeFileName(process.BizId)}_{document.DocumentSort:D2}_{SafeFileName(document.DocumentName)}_已签署.pdf",
|
||||
signedPdf);
|
||||
document.SignedPdfFileId = pdfFileId;
|
||||
document.UpdateTime = DateTime.Now;
|
||||
await _db.Updateable(document).ExecuteCommandAsync();
|
||||
if (!document.SignedPdfFileId.HasValue)
|
||||
{
|
||||
var signedPdf = await _qiyuesuoClient.DownloadDocument(document.ProviderDocumentId);
|
||||
document.SignedPdfFileId = await _fileService.StoreGeneratedFile(
|
||||
SysDictConst.FILE_ENGINE_ALIYUN_OSS,
|
||||
$"{SafeFileName(process.BizId)}_{document.DocumentSort:D2}_{SafeFileName(document.DocumentName)}_已签署.pdf",
|
||||
signedPdf);
|
||||
document.UpdateTime = DateTime.Now;
|
||||
await _db.Updateable(document).ExecuteCommandAsync();
|
||||
}
|
||||
// 中断重试时仍回填合同指针,不能因文档已落库而跳过未完成的关联更新。
|
||||
var pdfFileId = document.SignedPdfFileId.Value;
|
||||
await _db.Updateable<ObTaskContract>()
|
||||
.SetColumns(item => new ObTaskContract
|
||||
{
|
||||
GeneratedPdfFileId = pdfFileId,
|
||||
ContractStatus = TaskContractStatus.Archived
|
||||
})
|
||||
.Where(item => item.Id == document.TaskContractId)
|
||||
.Where(item => item.Id == document.TaskContractId && process.IsCurrent == true)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user