-
Notifications
You must be signed in to change notification settings - Fork 123
OpenAPIGenerator upgrade to v7.16.0 - [2] Added new mustache templates #1208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v7-generator/1-add-core-classes
Are you sure you want to change the base?
OpenAPIGenerator upgrade to v7.16.0 - [2] Added new mustache templates #1208
Conversation
Remove old mustache templates
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request is a significant upgrade, replacing old templates with new ones for the generichost library to support OpenAPI Generator v7.16.0. The changes are extensive and introduce a new structure for C# code generation. My review of the new mustache templates has identified a few critical and high-severity issues related to null handling, incorrect logic in authentication flows, and attempts to instantiate abstract classes. These could lead to runtime exceptions or unexpected behavior in the generated code. I've provided detailed feedback and code suggestions to improve the robustness and correctness of the new templates.
| catch (global::System.FormatException) | ||
| { | ||
| StringReader str = new StringReader(pvkstr); | ||
|
|
||
| //-------- read PEM encryption info. lines and extract salt ----- | ||
| if (!str.ReadLine(){{nrt!}}.StartsWith("Proc-Type: 4,ENCRYPTED")) // TODO: what do we do here if ReadLine is null? | ||
| return null; | ||
|
|
||
| String saltline = str.ReadLine(){{nrt!}}; // TODO: what do we do here if ReadLine is null? | ||
| if (!saltline.StartsWith("DEK-Info: DES-EDE3-CBC,")) | ||
| return null; | ||
|
|
||
| String saltstr = saltline.Substring(saltline.IndexOf(",") + 1).Trim(); | ||
| byte[] salt = new byte[saltstr.Length / 2]; | ||
| for (int i = 0; i < salt.Length; i++) | ||
| salt[i] = Convert.ToByte(saltstr.Substring(i * 2, 2), 16); | ||
|
|
||
| if (!(str.ReadLine() == "")) | ||
| return null; | ||
|
|
||
| //------ remaining b64 data is encrypted RSA key ---- | ||
| String encryptedstr = str.ReadToEnd(); | ||
|
|
||
| try | ||
| { //should have b64 encrypted RSA key now | ||
| binkey = Convert.FromBase64String(encryptedstr); | ||
| } | ||
| catch (global::System.FormatException) | ||
| { //data is not in base64 format | ||
| return null; | ||
| } | ||
|
|
||
| // TODO: what do we do here if keyPassPhrase is null? | ||
| byte[] deskey = GetEncryptedKey(salt, keyPassPhrase{{nrt!}}, 1, 2); // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes | ||
| if (deskey == null) | ||
| return null; | ||
|
|
||
| //------ Decrypt the encrypted 3des-encrypted RSA private key ------ | ||
| byte[]{{nrt?}} rsakey = DecryptKey(binkey, deskey, salt); //OpenSSL uses salt value in PEM header also as 3DES IV | ||
|
|
||
| return rsakey; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This catch block has several potential NullReferenceException issues and lacks proper error handling for encrypted keys without a passphrase.
str.ReadLine()can returnnull, but the null-forgiving operator (!) is used, which can lead to a crash. You should use null-conditional access (?.).- If an encrypted key is provided without a
keyPassPhrase, the code will crash at line 450. There should be a check for a nullkeyPassPhrasebefore attempting to decrypt the key.
I suggest refactoring this block for safer null handling and clearer error reporting.
catch (global::System.FormatException)
{
StringReader str = new StringReader(pvkstr);
//-------- read PEM encryption info. lines and extract salt -----
if (str.ReadLine()?.StartsWith("Proc-Type: 4,ENCRYPTED") != true)
return null;
String saltline = str.ReadLine();
if (saltline?.StartsWith("DEK-Info: DES-EDE3-CBC,") != true)
return null;
String saltstr = saltline.Substring(saltline.IndexOf(",") + 1).Trim();
byte[] salt = new byte[saltstr.Length / 2];
for (int i = 0; i < salt.Length; i++)
salt[i] = Convert.ToByte(saltstr.Substring(i * 2, 2), 16);
if (!(str.ReadLine() == ""))
return null;
//------ remaining b64 data is encrypted RSA key ----
String encryptedstr = str.ReadToEnd();
try
{ //should have b64 encrypted RSA key now
binkey = Convert.FromBase64String(encryptedstr);
}
catch (global::System.FormatException)
{ //data is not in base64 format
return null;
}
if (keyPassPhrase == null)
throw new ArgumentException("A passphrase is required for an encrypted private key.", nameof(keyPassPhrase));
byte[] deskey = GetEncryptedKey(salt, keyPassPhrase, 1, 2); // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes
if (deskey == null)
return null;
//------ Decrypt the encrypted 3des-encrypted RSA private key ------
byte[]{{nrt?}} rsakey = DecryptKey(binkey, deskey, salt); //OpenSSL uses salt value in PEM header also as 3DES IV
return rsakey;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This template is used in two test files, I've removed them here
| /// <inheritdoc/> | ||
| public bool IsValidHmacSignature(string json, string hmacSignature) | ||
| { | ||
| return {{packageName}}.{{corePackageName}}.Utilities.HmacValidatorUtility.IsHmacSignatureValid(hmacSignature, _adyenHmacKey, json); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation of IsValidHmacSignature has a critical flaw: it uses the _adyenHmacKey field which is never initialized, causing HMAC validation to always use a null key.
To fix this and follow best practices, I recommend the following changes:
- Store the provider: In the
{{apiName}}Handlerconstructor, store the injectedITokenProvider<HmacKeyToken>in a private readonly field (e.g.,_hmacKeyProvider). - Make validation async: Change
IsValidHmacSignatureto be anasyncmethod (e.g.,IsValidHmacSignatureAsync) in both the{{interfacePrefix}}{{apiName}}Handlerinterface and the{{apiName}}Handlerclass. This is crucial to avoid blocking on I/O when retrieving the key. - Implement async logic: In the new async method,
awaitthe key from_hmacKeyProvider.GetAsync()and then perform the validation.
This approach ensures correct, non-blocking HMAC validation.
| default: | ||
| break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default case in this switch statement does nothing, which means if an unsupported OAuthFlow is provided, the _grantType field will remain uninitialized. This will likely cause a null value to be sent in the token request later. It's better to throw an exception for unsupported flows to fail early and clearly.
default:
throw new NotSupportedException($"The OAuth flow '{flow}' is not supported.");
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mustache template is unused
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gcatanese Q: Do we leave this in? I've only included it for completeness as part of the v7 generator upgrade
templates-v7/csharp/libraries/generichost/HttpSigningConfiguration.mustache
Show resolved
Hide resolved
Remove unused templates ApiTests, DependencyInjectionTests #1208 (comment)
|
@gcatanese The mustache templates include the generated templates for the classes in the |
PR-2 of #1204
Description
This PR introduces the
mustache.templatesneeded for the upgrade of the OpenApiGenerator to v7.16.0 used in the Adyen sdk-automation to generate .NET models & services from the Adyen OpenAPI Specifications.We've always removed the .NET6.0 (= end of life support) workflow as we'll continue on .NET 8.0+