Skip to content
Snippets Groups Projects
FunctionalBaseClass.cs 6.23 KiB
Newer Older
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Security.Cryptography;
using System.Text;
using FitConnect.Models;
using Microsoft.Extensions.Logging;

namespace FitConnect;

public class FitConnectEnvironments {
    /// <summary>
    /// Default constructor.
    /// </summary>
    /// <param name="tokenUrl">URL for receiving the OAuth token</param>
    /// <param name="submissionApi">URL for the submission API</param>
    /// <param name="routingApi">URL for the routing API</param>
    public FitConnectEnvironments(string tokenUrl, string[] submissionApi, string routingApi) {
        TokenUrl = tokenUrl;
        SubmissionApi = submissionApi;
        RoutingApi = routingApi;
    }

    /// <summary>
    /// URL for receiving the OAuth token.
    /// </summary>
    public string TokenUrl { get; }

    /// <summary>
    /// URL for the submission API.
    /// </summary>
    public string[] SubmissionApi { get; }

    /// <summary>
    /// URL for the routing API.
    /// </summary>
    public string RoutingApi { get; }

    public enum EndpointType {
        Development,
        Testing,
        Production
    }

    /// <summary>
    /// Creates the endpoints for the given environment.
    /// </summary>
    /// <param name="endpointType">Environment to get endpoints for</param>
    /// <returns></returns>
    /// <exception cref="ArgumentException">Not all environments are ready to use</exception>
    public static FitConnectEnvironments Create(EndpointType endpointType) {
        return endpointType switch {
            EndpointType.Development => DevEnvironments,
            EndpointType.Testing => throw new ArgumentException("Not approved for online testing"),
            EndpointType.Production => throw new ArgumentException("NOT PRODUCTION READY"),
            _ => throw new ArgumentOutOfRangeException(nameof(endpointType), endpointType, null)
        };
    }

    private static readonly FitConnectEnvironments DevEnvironments = new(
        "https://auth-testing.fit-connect.fitko.dev/token",
        new []{"https://submission-api-testing.fit-connect.fitko.dev"},
        "https://routing-api-testing.fit-connect.fitko.dev"
    private static readonly FitConnectEnvironments TestEnvironments = new(
        "https://auth-testing.fit-connect.fitko.dev/token",
        new []{"https://submission-api-testing.fit-connect.fitko.dev"},
        "https://routing-api-testing.fit-connect.fitko.dev"
    );

    private static readonly FitConnectEnvironments ProductionEnvironments = new(
        "https://auth-testing.fit-connect.fitko.dev/token",
        new []{"https://submission-api-testing.fit-connect.fitko.dev"},
        "https://routing-api-testing.fit-connect.fitko.dev"
    );
}

public abstract class FunctionalBaseClass {
    protected readonly ILogger? logger;
    private RSA _rsa;
    public FitConnectEnvironments Environments { get; }
    protected FunctionalBaseClass(ILogger? logger, FitConnectEnvironments? endpoints) {
        Environments = endpoints ??
                    FitConnectEnvironments.Create(FitConnectEnvironments.EndpointType.Development);

        this.logger = logger;
    }


    /// <summary>
    /// Requesting an OAuth token from the FitConnect API.
    /// 
    /// You can get the Client ID and Client Secret from the FitConnect Self Service portal
    /// under https://portal.auth-testing.fit-connect.fitko.dev
    /// </summary>
    /// <param name="clientId">Your client Id</param>
    /// <param name="clientSecret">Your client Secret</param>
    /// <param name="scope">Scope if needed</param>
    /// <returns></returns>
    public async Task<OAuthAccessToken?> GetTokenAsync(string clientId, string clientSecret,
        string? scope = null) {
        var client = new HttpClient();
        client.DefaultRequestHeaders.Accept.Add(
            MediaTypeWithQualityHeaderValue.Parse("application/json"));

        var requestContent = new Dictionary<string, string> {
            { "grant_type", "client_credentials" },
            { "client_id", clientId },
            { "client_secret", clientSecret }
        };

        if (scope != null)
            requestContent["scope"] = scope;

        var content = new FormUrlEncodedContent(requestContent);

        var request = new HttpRequestMessage(HttpMethod.Post, Environments.TokenUrl) {
            Content = content,
            Method = HttpMethod.Post
        };

        var response = await client.SendAsync(request);

        return await response.Content.ReadFromJsonAsync<OAuthAccessToken>();
    }

    public Task<SecurityEventToken> GetSetDataAsync() {
        throw new NotImplementedException();
    }

    public byte[] EncryptDataAsync(byte[] data,
        byte[]? publicKey,
        string? password,
        int numberOfIterations) {
        _rsa = RSA.Create(2048);
        // _rsa.ImportRSAPublicKey(publicKey, out var read);

        logger?.LogInformation(
            "Encrypting data with public key: {}",
            Convert.ToBase64String(_rsa.ExportRSAPublicKey()));

        // var keyParams = new PbeParameters(
        //     PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, numberOfIterations);
        //
        // var privateKey =
        //     rsa.ExportEncryptedPkcs8PrivateKey(Encoding.UTF8.GetBytes(password), keyParams);
        //
        // logger?.LogInformation(
        //     "Private key: {}", privateKey);

        return _rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
    }

    public byte[] DecryptDataAsync(byte[] data, byte[] privateKey) {
        return _rsa.Decrypt(data, RSAEncryptionPadding.OaepSHA256);
    }


    private async Task<T?> RestCall<T>(Uri uri, HttpMethod method, string body) {
        var client = new HttpClient();
        client.DefaultRequestHeaders.Add("Accept", "application/json");
        client.DefaultRequestHeaders.Add("Content-Type", "application/json");

        var request = new HttpRequestMessage();
        request.Method = method;
        request.Content = new StringContent(body, Encoding.UTF8, "application/json");
        request.RequestUri = uri;

        var response = await client.SendAsync(request);

        if (response.IsSuccessStatusCode)
            return (await response.Content.ReadFromJsonAsync<T>());

        throw new HttpRequestException("Error calling FitConnect API");
    }
}