Skip to content

To fix incorrect Rust code on multiple apiKeys #8868

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

nappa85
Copy link

@nappa85 nappa85 commented Mar 2, 2021

To fix #8833

PR checklist

  • Read the contribution guidelines.
  • Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community.
  • Run the following to build the project and update samples:
    ./mvnw clean package 
    ./bin/generate-samples.sh
    ./bin/utils/export_docs_generators.sh
    
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    For Windows users, please run the script in Git BASH.
  • File the PR against the correct branch: master, 5.1.x, 6.0.x
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

@wing328
Copy link
Member

wing328 commented Mar 3, 2021

Please update the samples by running:

./mvnw clean package 
./bin/generate-samples.sh
./bin/utils/export_docs_generators.sh

@wing328
Copy link
Member

wing328 commented Mar 3, 2021

cc @frol (2017/07) @farcaller (2017/08) @richardwhiuk (2019/07) @paladinzh (2020/05)

@wing328 wing328 added this to the 5.1.0 milestone Mar 3, 2021
@wing328 wing328 changed the title Proposed solution for issue 8833 To fix incorrect Rust code on multiple apiKeys Mar 3, 2021
@wing328
Copy link
Member

wing328 commented Mar 4, 2021

Is it correct to say that this is a breaking change?

What if the API doesn't use API key for authentication? For example, it only uses HTTP basic for authentication.

@nappa85
Copy link
Author

nappa85 commented Mar 4, 2021

Is it correct to say that this is a breaking change?

What if the API doesn't use API key for authentication? For example, it only uses HTTP basic for authentication.

You need to specify a type that impls ApiKey, even if not using it.
E.g:

let conf = Configuration::<String>::default();

But this approach allows dynamic ApiKeys, for example in my use case there is a nonce header that must be different and incremental for every call, and a signature header that's an HMAC based on a secret, the nonce and the URL.
With a basic HashMap approach (the minimum for multiple keys support) I would need to keep a mutable instance of Configuration and keep editing the keys, having to foresee the URL that will be composed with GET parameters.
With my approach I simply need a struct that impls ApiKey, it's everything simpler and more dynamic.

I think it's a standard Rust approach.

A retrocompatibility approach could be not exporting plain Configuration struct, but adding to parent mod a

pub type Configuration = configuration::Configuration<String>;

@wing328
Copy link
Member

wing328 commented Mar 4, 2021

@nappa85 what about following other clients and use a hash to store the API key instead?

e.g. Configuration.cs in the C# client: https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/csharp/OpenAPIClient/src/Org.OpenAPITools/Client/Configuration.cs#L88-L98

There's also something call API key prefix but it's not something that needs to be included in this PR.

@nappa85
Copy link
Author

nappa85 commented Mar 4, 2021

@nappa85 what about following other clients and use a hash to store the API key instead?

e.g. Configuration.cs in the C# client: https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/csharp/OpenAPIClient/src/Org.OpenAPITools/Client/Configuration.cs#L88-L98

There's also something call API key prefix but it's not something that needs to be included in this PR.

It's a less powerful approach, and, as you already told, it doesn't support the prefixes.

In my use case I had to expand my approach passing also a reference to the RequestBuilder to be able to retrieve already setted headers and the URL:

use openapi::apis::configuration::ApiKey;

use reqwest::RequestBuilder;

use chrono::Utc;

use hmac::{Hmac, Mac, NewMac};

use log::error;

type HmacSha512 = Hmac<sha2::Sha512>;

/// TheRockTrading ApiKeys manager
pub struct TrtKeys {
    api_key: String,
    secret: String,
}

impl TrtKeys {
    /// costructor
    pub fn new(api_key: String, secret: String) -> Self {
        TrtKeys {
            api_key,
            secret
        }
    }
}

impl ApiKey for TrtKeys {
    fn get_prefix(&self, _: &str) -> Option<String> {
        None
    }
    fn get_key(&self, name: &str, req_builder: &RequestBuilder) -> Option<String> {
        match name {
            "X-TRT-KEY" => Some(self.api_key.clone()),
            "X-TRT-NONCE" => {
                let timestamp = Utc::now().timestamp_nanos();
                Some(timestamp.to_string())
            },
            "X-TRT-SIGN" => {
                let rb = req_builder.try_clone()?;
                let req = rb.build()
                    .map_err(|e| error!("error building request: {}", e))
                    .ok()?;
                let nonce = req.headers().get("X-TRT-NONCE")?;
                let mut mac = HmacSha512::new_varkey(self.secret.as_bytes())
                    .map_err(|e| error!("error initializing HMAC-SHA521: {}", e))
                    .ok()?;

                // this way we skip the utf8 check
                let mut bytes = nonce.as_bytes().to_vec();
                let mut url = req.url().to_string().into_bytes();
                bytes.append(&mut url);
                mac.update(&bytes);

                Some(hex::encode(mac.finalize().into_bytes()))
            },
            _ => None,
        }
    }
}

I think it's a poweful example

@wing328 wing328 modified the milestones: 5.1.0, 5.1.1 Mar 19, 2021
@7Hazard
Copy link

7Hazard commented Aug 18, 2024

It's evident this has been forgotten about, but is still an issue in 7.7.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] Incorrect Rust code on multiple apiKeys
3 participants