in src/ccf/ccf-provider-client/Controllers/NetworksController.cs [324:482]
public async Task<IActionResult> RecoverNetwork(
[FromRoute] string networkName,
[FromBody] RecoverNetworkInput content)
{
var error = ValidateRecoverInput();
if (error != null)
{
return error;
}
CcfNetworkProvider ccfNetworkProvider = this.GetNetworkProvider(content.InfraType);
CcfNetwork network;
if (content.OperatorRecovery != null)
{
using RSA rsaEncKey =
!string.IsNullOrEmpty(content.OperatorRecovery.EncryptionPrivateKey) ?
Utils.ToRSAKey(content.OperatorRecovery.EncryptionPrivateKey) :
await Utils.ToRSAKey(new Uri(content.OperatorRecovery.EncryptionKeyId!));
network = await ccfNetworkProvider.RecoverNetwork(
networkName,
content.NodeCount ?? 1,
content.NodeLogLevel,
SecurityPolicyConfigInput.Convert(content.SecurityPolicy),
content.PreviousServiceCertificate,
rsaEncKey,
content.ProviderConfig);
}
else
{
var svcName = content.ConfidentialRecovery!.RecoveryServiceName;
var svcProvider = this.GetRecoveryServiceProvider(content.InfraType);
var recoveryService = await svcProvider.GetService(
svcName,
content.ProviderConfig);
if (recoveryService == null)
{
return this.NotFound(new ODataError(
code: "ServiceNotFound",
message: $"No endpoint for service {svcName} was found."));
}
network = await ccfNetworkProvider.RecoverNetwork(
networkName,
content.NodeCount ?? 1,
content.NodeLogLevel,
SecurityPolicyConfigInput.Convert(content.SecurityPolicy),
content.PreviousServiceCertificate,
this.GetRecoveryAgentProvider(content.InfraType),
content.ConfidentialRecovery!.MemberName,
recoveryService,
content.ProviderConfig);
}
return this.Ok(network);
IActionResult? ValidateRecoverInput()
{
if (!string.IsNullOrEmpty(content.NodeLogLevel))
{
List<string> allowedValues =
[
"Trace", "Debug", "Info", "Fail", "Fatal"
];
if (!allowedValues.Contains(content.NodeLogLevel))
{
return this.BadRequest(new ODataError(
code: "InvalidNodeLogLevel",
message: $"Value should be one of: {string.Join(",", allowedValues)}"));
}
}
if (content.OperatorRecovery != null && content.ConfidentialRecovery != null)
{
return this.BadRequest(new ODataError(
code: "ConflictingInput",
message: "Both operatorRecovery and confidentialRecovery cannot be specified" +
" together."));
}
if (content.OperatorRecovery == null && content.ConfidentialRecovery == null)
{
return this.BadRequest(new ODataError(
code: "InputMissing",
message: "Either operatorRecovery or confidentialRecovery must be specified."));
}
try
{
using var c = X509Certificate2.CreateFromPem(content.PreviousServiceCertificate);
}
catch (Exception e)
{
return this.BadRequest(new ODataError(
code: "InvalidCertificate",
message: e.Message));
}
if (content.OperatorRecovery != null)
{
var opRec = content.OperatorRecovery;
if (string.IsNullOrEmpty(opRec.EncryptionPrivateKey) &&
string.IsNullOrEmpty(opRec.EncryptionKeyId))
{
return this.BadRequest(new ODataError(
code: "InvalidEncryptionKey",
message: "Either encryptionPrivateKey or encryptionKeyId must be specified."));
}
if (!string.IsNullOrEmpty(opRec.EncryptionPrivateKey) &&
!string.IsNullOrEmpty(opRec.EncryptionKeyId))
{
return this.BadRequest(new ODataError(
code: "InvalidEncryptionKey",
message: "Only one of encryptionPrivateKey or encryptionKeyId must be specified."));
}
if (!string.IsNullOrEmpty(opRec.EncryptionPrivateKey))
{
try
{
using var rsa = RSA.Create();
rsa.ImportFromPem(opRec.EncryptionPrivateKey);
}
catch (Exception e)
{
return this.BadRequest(new ODataError(
code: "InvalidEncryptionPrivateKey",
message: e.Message));
}
}
else
{
try
{
new Uri(opRec.EncryptionKeyId!);
}
catch (Exception e)
{
return this.BadRequest(new ODataError(
code: "InvalidEncryptionKeyId",
message: e.Message));
}
}
}
if (content.ConfidentialRecovery != null)
{
if (string.IsNullOrEmpty(content.ConfidentialRecovery.MemberName))
{
return this.BadRequest(new ODataError(
code: "InputMissing",
message: "confidentialRecovery.memberName must be specified."));
}
}
return null;
}
}