Archive

Archive for January, 2023

Evaluate C# with C# using #Roslyn

Having code that evaluates code is a bit of an unusual ask, but perhaps, you want to have a super-configurable system, where you can dynamically execute user code, giving full flexibility over the functionality of your system. Obviously this opens security issues, but let’s imagine you are in a secure, trusted environment

So, this is where Roslyn comes in, Which you can load by grabbing the NuGet package using “Install-Package Microsoft.CodeAnalysis.CSharp.Scripting”. Then, you can run a very simple command such as;

var result = CSharpScript.EvaluateAsync("1 + 3").Result;

All very simple, however, let’s say you want to run more complex code. Here, for example, to run some code to get the user’s IP address. I’ve moved this out to a seperate file, called Sample.txt, and set the build option to copy always, so I can write the user code in a different location to the interpreting code.

var wc = new WebClient();
return wc.DownloadString("http://www.icanhazip.com");

If you try to run this as a script, it borks, because it can’t locate WebClient, and fully qualifying it, by saying System.Net.WebClient doesn’t work either, because it can’t locate System.Net either, so you need to add a bit more as follows –

var scriptOptions = ScriptOptions.Default;
var asmWebClient = typeof(WebClient).Assembly;
scriptOptions = scriptOptions.AddReferences(asmWebClient);
scriptOptions = scriptOptions.AddImports("System.Net");
var sample = File.ReadAllText("sample.txt");
var result = CSharpScript.EvaluateAsync(sample, scriptOptions).Result;
Console.WriteLine(result);

This grabs the relevant assembly for WebClient, and then adds both the reference, and the import to the script. Once it executes, it can find the WebClient class, and the code runs.

GitHub Repo here: https://github.com/infiniteloopltd/RoslynDemo

Categories: Uncategorized

#Excel tip: Formula to cross check ledger transactions

This is a real time saver, and I hope it’s useful to someone else.

If you have a typical “ledger” type spread sheet, with columns, payments in, payments out and balance – based on the image above. Perhaps this has been entered manually, or perhaps it’s been OCR’d from paper, there could be errors in it, and it can take alot of time to manually check each number.

In the example above you can see there must be an issue with the value in Cell D4, since the Balance does not reflect the value. However, getting excel to highlight this error would allow you to manually check that one cell, not every value on the spreadsheet.

So, I added a new cell in G3 with the value =$E$2+SUM($D$3:D3)-SUM($C$3:C3) and copied this for each row in the spreadsheet. Then added a conditional formatting rule; of =$G1<>$E1

Which then highlights what the Balance should be for each row, and highlights it, if the balance is different to that stated. In this case, you can see that after a point, the projected Balance diverges from the stated balance, indicating the row at which an inaccuracy is present.

Correcting this value, and the projected balance now matches the stated balance, without having to check every single value on the spreadsheet.

Categories: Uncategorized

Add a #FingerPrint reader to a C# WinForms app

Probably a good way to add extra security to a Windows Form app, just to make sure that there is a real human user infront of the screen, and it’s not some bot trying to interact with your software, is to add a Fingerprint / “Windows Hello” login. Of course, in the real world, generally the attacker would probably try to de-compile your software and try to attack whatever underlying API you are using. However, this is a very visible security feature, and if you’re looking for a super-quick security addition, then, this may be an interesting addition.

Windows Hello is a biometric authentication feature that allows users to log into their Windows device using a fingerprint scanner, facial recognition, or other biometric methods, rather than a password.

Some potential use cases for including Windows Hello in a WinForms app include:

  • Secure login: By using a fingerprint scanner or other biometric method, you can add an additional layer of security to your app and make it more difficult for unauthorized users to access the app.
  • Convenience: Allowing users to log in with a fingerprint or other biometric method can make the login process more convenient for them, as they don’t have to remember a password or enter it manually.
  • Compliance: Depending on the nature of the app and the industries it serves, biometric authentication may be required by compliance regulations or industry standards.
  • User experience: For some users, biometric authentication is a preferred way to interact with their devices, and they feel more secure with that kind of security.
  • Protecting sensitive data: If your app handles sensitive information, such as financial data or personal information, biometric authentication can help ensure that only authorized users have access to this information.

Here is a link to a public GitHub Repo that shows a simple example of this in action: https://github.com/infiniteloopltd/FingerPrintReader

The Key code being;

var supported = await KeyCredentialManager.IsSupportedAsync();
if (!supported) return;
var result =
	await KeyCredentialManager.RequestCreateAsync("login",
		KeyCredentialCreationOption.ReplaceExisting);
if (result.Status == KeyCredentialStatus.Success)
{
	MessageBox.Show("Logged in.");
}
else
{
	MessageBox.Show("Login failed.");
}
Categories: Uncategorized

AvatarAPI now includes #GitHub as a source

AvatarAPI.com is an API that allows you get images, names , and sometimes addresses from an email address, depending on what source / provider is used.

Today, GitHub is the latest addition to the source list, which means that anyone with a public email address on their GitHub profile can be searched, returning the avatar icon, and the account name.

A handful of potential use cases for this API are as follows;

  1. Social media and networking apps can use the API to automatically populate user profiles with their contact’s profile pictures and names.
  2. Email clients can use the API to display the sender’s profile picture and name in the email’s header.
  3. Customer relationship management (CRM) software can use the API to associate a customer’s email address with their profile picture and name.
  4. Online marketplaces and e-commerce platforms can use the API to show a buyer’s profile picture and name on their account page.
  5. Collaboration and productivity tools can use the API to display a team member’s profile picture and name in a shared document or project management platform.
  6. Security and authentication systems can use the API to verify the identity of a user based on their email address and associated profile picture and name.
  7. Online gaming and virtual reality platforms can use the API to display a player’s profile picture and name in-game or on a leaderboard.
  8. Educational and training platforms can use the API to associate a student’s email address with their profile picture and name in a virtual classroom.
Categories: Uncategorized

Checking a Spanish #VAT number using the #VIES webservice in C#

Checking EU VAT numbers using the VIES webservice has some quirks, for example, in Germany, only the validity of the number can be verified, and in Spain, although the company name and address are not exposed, the API can be used to verify them against provided details, for this, a different service method needs to be used for Spain, than for other countries;

TL; DR; here is the Github Repo showing the code in c# https://github.com/infiniteloopltd/CheckVatNumberSpain

Checking a VAT number in Spain can be done by using the European Union’s VAT Information Exchange System (VIES). VIES is a web-based system that allows businesses and tax authorities in the EU to verify the validity of VAT numbers assigned to companies in other EU member states.

To check a VAT number in Spain using VIES, you would need to make a SOAP web service request to the VIES web service endpoint, passing in the VAT number you wish to validate as a parameter. The request would be sent to the VIES service over HTTPS, ensuring the data transmitted is secure.

The VIES service would then respond with a validation result indicating whether the VAT number is valid or not. If the VAT number is valid, the response would also include the country code of the member state that issued the VAT number. The VIES service does not expose the name or address of the company.

Added in the code is a inspector that prints to the console the XML being sent and received, for use in Postman, or another client that needed to POST the XML via HTTP rather than SOAP; which would be;

Sample Request

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <checkVatApprox xmlns="urn:ec.europa.eu:taxud:vies:services:checkVat:types">
      <countryCode>ES</countryCode>
      <vatNumber>B83891812</vatNumber>
      <traderName>Rodrisa Automoviles</traderName>
      <traderCompanyType />
      <traderStreet>Avda. Reina Victoria</traderStreet>
      <traderPostcode>28430</traderPostcode>
      <traderCity>Madrid</traderCity>
      <requesterCountryCode />
      <requesterVatNumber />
    </checkVatApprox>
  </s:Body>
</s:Envelope>

Sample Response

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
    <env:Header/>
    <env:Body>
        <ns2:checkVatApproxResponse xmlns:ns2="urn:ec.europa.eu:taxud:vies:services:checkVat:types">
            <ns2:countryCode>ES</ns2:countryCode>
            <ns2:vatNumber>B83891812</ns2:vatNumber>
            <ns2:requestDate>2023-01-12+01:00</ns2:requestDate>
            <ns2:valid>true</ns2:valid>
            <ns2:traderName>Rodrisa Automoviles</ns2:traderName>
            <ns2:traderCompanyType></ns2:traderCompanyType>
            <ns2:traderStreet>Avda. Reina Victoria</ns2:traderStreet>
            <ns2:traderPostcode>28430</ns2:traderPostcode>
            <ns2:traderCity>Madrid</ns2:traderCity>
            <ns2:traderNameMatch>1</ns2:traderNameMatch>
            <ns2:traderCompanyTypeMatch>3</ns2:traderCompanyTypeMatch>
            <ns2:traderStreetMatch>1</ns2:traderStreetMatch>
            <ns2:traderPostcodeMatch>1</ns2:traderPostcodeMatch>
            <ns2:traderCityMatch>2</ns2:traderCityMatch>
            <ns2:requestIdentifier></ns2:requestIdentifier>
        </ns2:checkVatApproxResponse>
    </env:Body>
</env:Envelope>
Categories: Uncategorized

Clearing out #AWS #Cloudwatch in C# – Coded with help from #ChatGPT

If you’re like me, you use AWS Cloudwatch when testing and debugging your Lambda functions on AWS, and then whenever your code is working, you end up leaving them in, “just in case” – Of course, that means you ignore them, until you get a bill from AWS for holding GB’s of logs, for no reason whatsoever.

So, here’s some C# code (Coded with the help of ChatCPT OpenAI with some modifications), to clear out all your Cloudwatch logs in all regions. You can be less heavy-handed, but I wanted to delete everything.

using Amazon;
using Amazon.CloudWatchLogs;
using Amazon.CloudWatchLogs.Model;
using Amazon.Runtime;

class Program
{
    static void Main(string[] args)
    {
        const string accessKey = "xxxxxxxxxxxxxxx";
        const string secretKey = "xxxxxxxxxxxxxxx";

        var credentials = new BasicAWSCredentials(accessKey, secretKey);
        foreach (var region in Amazon.RegionEndpoint.EnumerableAllRegions)
        {
            Console.WriteLine(region.SystemName);
            var client = new AmazonCloudWatchLogsClient(credentials, region);
            try
            {
                // Get a list of all log groups
                DescribeLogGroupsResponse logGroupsResponse = null;
                try
                {
                    logGroupsResponse = client.DescribeLogGroupsAsync().Result;
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    continue;
                }
                var logGroups = logGroupsResponse.LogGroups;

                // Iterate through each log group and delete it
                foreach (var logGroup in logGroups)
                {
                    // Get a list of all streams in the log group
                    var logStreamsResponse = client.DescribeLogStreamsAsync(new DescribeLogStreamsRequest
                    {
                        LogGroupName = logGroup.LogGroupName
                    }).Result;
                    var logStreams = logStreamsResponse.LogStreams;

                    // Iterate through each stream and delete it
                    foreach (var logStream in logStreams)
                    {
                        client.DeleteLogStreamAsync(new DeleteLogStreamRequest
                        {
                            LogGroupName = logGroup.LogGroupName,
                            LogStreamName = logStream.LogStreamName
                        });
                        Thread.Sleep(TimeSpan.FromMilliseconds(50));
                        Console.WriteLine("Deleted log stream: " + logStream.LogStreamName + " in log group: " + logGroup.LogGroupName);
                    }

                    client.DeleteLogGroupAsync(new DeleteLogGroupRequest
                    {
                        LogGroupName = logGroup.LogGroupName
                    });
                    Thread.Sleep(TimeSpan.FromMilliseconds(50));
                    Console.WriteLine("Deleted log group: " + logGroup.LogGroupName);
                }

                Console.WriteLine("Deleted all log groups and streams in region: " + region.SystemName);
            }
            catch (AmazonCloudWatchLogsException e)
            {
                Console.WriteLine("Error while processing region " + region.SystemName);
                Console.WriteLine("Caught Exception: " + e.Message);
                Console.WriteLine("Response Status Code: " + e.StatusCode);
                Console.WriteLine("Error Code: " + e.ErrorCode);
                Console.WriteLine("Error Type: " + e.ErrorType);
                Console.WriteLine("Request ID: " + e.RequestId);
            }
        }
    }
}

Hope this helps someone!

Categories: Uncategorized

Comparing #AWS S3 Upload via CLI to #Azure Blob upload via CLI.

The AWS Command Line Interface (CLI) is a unified tool to manage AWS services. With just one tool to download and configure, you can control multiple AWS services from the command line and automate them through scripts.

The Azure Command-Line Interface (CLI) is a set of commands used to create and manage Azure resources. It is available on Windows, macOS, and Linux.

Both the AWS CLI and Azure CLI allow you to manage cloud resources from the command line and automate them through scripts. However, there are some key differences to be aware of:

  • Services: AWS offers a wider range of services, but Azure has some services that AWS does not, such as Azure Arc for managing hybrid environments.
  • Language support: The AWS CLI supports multiple programming languages, including Python, Node.js, and C#. The Azure CLI is written in Node.js and is designed to be used with the Azure Resource Manager.
  • Installation and setup: The AWS CLI is installed using a package manager or by downloading a standalone binary. The Azure CLI is installed using a package manager or by downloading the installer.

Overall, both the AWS CLI and Azure CLI are powerful tools that allow you to manage and automate your cloud resources. It really comes down to which cloud platform you are using and which services you need to manage.

Both the AWS and Azure CLI make it easy to upload files, but lets take a look at the difference

To login you type AWS Configure for AWS or AZ login for azure. the AZ login opens a browser so you can provide your credentials, whereas AWS Configure prompts for a IAM user key and secret. In my opinion, AZ makes this process easier for a first time user, but AWS tends to guide you towards the principle of least access better, so more secure for the novice user.

AWS arranges it’s S3 storage into buckets, and optionally folders within the buckets. Azure has storage accounts, and you must have at least one container within the storage account.

To upload a file on Azure it’s

az storage blob upload -f backup.zip -c database-backups –account-name backupaccount

And the same on AWS is:

aws s3 cp backup.zip s3://backupaccount/

Some complexities I had found with both Azure and AWS, is if you have multiple accounts, or subscriptions. In Azure, you have to select your subscription as follows;

az account set –subscription “PayAsYouGo”

Wheras, you can have multiple profiles in AWS, and that is selected using

aws s3 cp backup.zip s3://backupaccount/ –profile AWS

Categories: Uncategorized