<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Bits & Bytes]]></title><description><![CDATA[Pragmatic opinions to real world problems.]]></description><link>https://blog.lionelchetty.dev/</link><image><url>https://blog.lionelchetty.dev/favicon.png</url><title>Bits &amp; Bytes</title><link>https://blog.lionelchetty.dev/</link></image><generator>Ghost 2.25</generator><lastBuildDate>Fri, 17 Apr 2026 04:41:59 GMT</lastBuildDate><atom:link href="https://blog.lionelchetty.dev/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Using Functions Outside Azure]]></title><description><![CDATA[<p>I'm not a tease so here it is, tested with what's currently available as of this post. Following the <a href="https://blog.lionelchetty.dev/using-kudu-outside-azure/">previous post, you now have Kudu</a> so it's time to use it!  </p><!--kg-card-begin: markdown--><p>Go ahead and create a new app in kudu-admin.<br>
Notice that the Application URL isn't bound to localhost on</p>]]></description><link>https://blog.lionelchetty.dev/using-functions-outside-azure/</link><guid isPermaLink="false">6817373c3c5c7797704eb540</guid><category><![CDATA[Azure]]></category><category><![CDATA[Functions]]></category><category><![CDATA[Kudu]]></category><category><![CDATA[Microsoft]]></category><dc:creator><![CDATA[Lionel Christopher Chetty]]></dc:creator><pubDate>Sun, 04 May 2025 14:06:05 GMT</pubDate><media:content url="https://blog.lionelchetty.dev/content/images/2025/05/using-func-outside-azure.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.lionelchetty.dev/content/images/2025/05/using-func-outside-azure.jpg" alt="Using Functions Outside Azure"><p>I'm not a tease so here it is, tested with what's currently available as of this post. Following the <a href="https://blog.lionelchetty.dev/using-kudu-outside-azure/">previous post, you now have Kudu</a> so it's time to use it!  </p><!--kg-card-begin: markdown--><p>Go ahead and create a new app in kudu-admin.<br>
Notice that the Application URL isn't bound to localhost on a port, I removed the binding but remember the port as we'll need it later.<br>
<img src="https://blog.lionelchetty.dev/content/images/2025/05/001.jpg" alt="Using Functions Outside Azure"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Now to get the <a href="https://github.com/Azure/azure-functions-host/releases/tag/v4.839.400">Azure Functions host/runtime</a>, naming things is hard so we'll assume <code>FunctionsInProc8.4.839.400.zip</code> means In-Process v4 using .NET 8 LTS. I also tested the non-in-proc version and it did work, note all my testing was x64.<br>
Extract the zip file as we'll be using the contents of the 64Bit folder.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>First we need to set some user environment variables.<br>
Who is the user? Your app is the user. <strong>Remember everything runs in the context of your application pool.</strong></p>
<p>Go to your app's Service/Kudu/SCM url, using the Kudu debug console run the following in the command prompt.</p>
<pre><code>setx AZURE_FUNCTIONS_ENVIRONMENT Development
setx FUNCTIONS_WORKER_RUNTIME dotnet
setx AzureWebJobsScriptRoot %home%\site\wwwroot
</code></pre>
<p>Then stop &amp; start your app's application pool.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>I won't be explaining everything about Web Jobs, better docs exist.<br>
We just need to create one continous job which requires 2 files, that will start our Azure Functions host.</p>
<p><code>settings.job</code></p>
<pre><code>{
    &quot;is_in_place&quot;: true,
    &quot;is_singleton&quot;: true
}
</code></pre>
<p><code>run.cmd</code></p>
<pre><code>call .\Microsoft.Azure.WebJobs.Script.WebHost.exe --urls &quot;http://localhost:{Application URL ORIGINAL PORT we unbound}&quot;
</code></pre>
<p>Your app's site dir should have a structure like below, <strong>I redacted the other files but don't remove them.</strong></p>
<pre><code>C:\kudu\apps\wtfunc\site
├───deployments
├───jobs
│   └───continuous
│       └───FunctionsInProc8.4.839.400
│           │   Microsoft.Azure.WebJobs.Script.WebHost.exe
│           │   run.cmd
│           │   settings.job
├───locks
└───wwwroot
    │   hostingstart.html
</code></pre>
<p>Kudu will pick up the job &amp; start the Azure Functions host.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>You can now go to <code>http://localhost:{Application URL ORIGINAL PORT}</code> but we still need to point the new Application URL hostname to the Azure Functions host.<br>
<img src="https://blog.lionelchetty.dev/content/images/2025/05/002.jpg" alt="Using Functions Outside Azure"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>To do this, we'll be using the <a href="https://www.iis.net/downloads/microsoft/url-rewrite">IIS URL Rewrite Module</a> with <a href="https://www.iis.net/downloads/microsoft/application-request-routing">Application Request Routing</a> for a simple <a href="https://github.com/dalion619/kudu-azfunc-sample/blob/main/web.config">web.config</a> to act as a reverse proxy.</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;configuration&gt;
    &lt;location path=&quot;&quot; allowOverride=&quot;false&quot;&gt;
        &lt;system.webServer&gt;
            &lt;handlers&gt;
                &lt;clear /&gt;
            &lt;/handlers&gt;
            &lt;rewrite&gt;
                &lt;rules&gt;
                    &lt;rule name=&quot;ReverseProxyInboundRule&quot; enabled=&quot;true&quot; stopProcessing=&quot;true&quot;&gt;
                        &lt;match url=&quot;(.*)&quot; /&gt;
                        &lt;conditions&gt;
                            &lt;add input=&quot;{CACHE_URL}&quot; pattern=&quot;^(https?)://&quot; /&gt;
                        &lt;/conditions&gt;
                        &lt;action type=&quot;Rewrite&quot; url=&quot;http://localhost:YOUR_HOST_POST/{R:1}&quot; /&gt;
                    &lt;/rule&gt;
                &lt;/rules&gt;
            &lt;/rewrite&gt;
        &lt;/system.webServer&gt;
    &lt;/location&gt;
&lt;/configuration&gt;
</code></pre>
<p><strong>Note the clearing of the handlers</strong>. The Azure Functions host should be executing binaries not your app's site. You can also create a new app pool for your app's site aspect with the .NET CLR version set to <code>No Managed code</code><br>
You can remove <code>hostingstart.html</code> from <code>wwwroot</code> so that <code>web.config</code> is the only file. Deployment is the same as Azure, you'll have a structure like below.</p>
<pre><code>C:\kudu\apps\wtfunc\site\wwwroot
│   host.json
│   web.config
└───TestHttp
        function.json
        run.csx
</code></pre>
<p>or</p>
<pre><code>C:\kudu\apps\wtfunc\site\wwwroot
│   extensions.csproj
│   host.json
│   web.config
├───bin
│       Aliencube.AzureFunctions.Extensions.Configuration.AppSettings.dll
│       Aliencube.AzureFunctions.Extensions.OpenApi.Core.dll
│       Aliencube.AzureFunctions.Extensions.OpenApi.dll
├───HelloWorld
│       function.json
│       function.proj
│       project.assets.json
│       run.csx
│
├───RenderSwaggerUI
│       function.json
│       function.proj
│       project.assets.json
│       run.csx
│
├───Shared
│       IOpenApiHttpTriggerContext.csx
│       JsonContentResult.csx
│       SwaggerGen.csx
│       SwaggerLoad.csx
│
└───Swagger
        function.json
        function.proj
        project.assets.json
        run.csx
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><img src="https://blog.lionelchetty.dev/content/images/2025/05/003.jpg" alt="Using Functions Outside Azure"><br>
That's it, your're good to go! <a href="https://github.com/dalion619/kudu-azfunc-sample">My code examples are on GitHub</a>. If you have issues, logs are in the data dir i.e. <code>C:\kudu\apps\wtfunc\data</code>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Lastly my soapbox diatribe.<br>
I wish MS invested 1/10th of what they did for co-pilot into C# scripting, csx is a different form of expression that allows you to be creative when solving dynamic problems.<br>
Functions + csx align with the words of Dijkstra &quot;<em>The purpose of abstracting is not to be vague, but to create a new semantic level in which one can be absolutely precise.</em>&quot;</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Using Kudu Outside Azure]]></title><description><![CDATA[<p>Once upon a time before Functions, we had Web Jobs on Azure App Services and the 'engine' behind it was Kudu. I originally planned to detail this out last year but with the <a href="https://github.com/projectkudu/kudu">project now archived</a> by MS it was now or never.</p><p>Kudu is not dead, the repo and</p>]]></description><link>https://blog.lionelchetty.dev/using-kudu-outside-azure/</link><guid isPermaLink="false">680ef4641cac5181d45e5522</guid><category><![CDATA[Azure]]></category><category><![CDATA[Kudu]]></category><category><![CDATA[Microsoft]]></category><dc:creator><![CDATA[Lionel Christopher Chetty]]></dc:creator><pubDate>Mon, 28 Apr 2025 14:15:38 GMT</pubDate><media:content url="https://blog.lionelchetty.dev/content/images/2025/04/using-kudu-outside-azure.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.lionelchetty.dev/content/images/2025/04/using-kudu-outside-azure.jpg" alt="Using Kudu Outside Azure"><p>Once upon a time before Functions, we had Web Jobs on Azure App Services and the 'engine' behind it was Kudu. I originally planned to detail this out last year but with the <a href="https://github.com/projectkudu/kudu">project now archived</a> by MS it was now or never.</p><p>Kudu is not dead, the repo and Azure were never like for like. The addition of support for Linux &amp; containers, means it's evolving. On Windows it was truly a showcase for the capabilities of IIS.</p><p>Now for the disclaimer. Kudu was built to support Azure PaaS and work within the Azure App Service's sandbox so somethings may not work without tweaking or never work such as RUN FROM PACKAGE/ZIP which I wish came to IIS as my anecdotal observation is that the read-only aspect provides a perf improvement across tech stacks &amp; platforms.</p><p>One of Kudu's initial developers, <a href="https://blog.davidebbo.com/2012/06/developing-kudu-locally-and-on-azure.html">David Ebbo did a post on running Kudu locally</a>. The other David Fowler, needs no introduction.<br>The gist is you need <a href="https://nodejs.org/en">Node.js</a> &amp; <a href="https://git-scm.com/downloads/win">Git</a> on the Windows instance where Kudu is going to be deployed.</p><p>The next step is to clone the repo &amp; build it, but if you're lazy and run random things from random people,<a href="https://github.com/dalion619/kudu/releases/tag/S100"> I've already done it for you</a>. You do you boo.<br>Now we have to create the folders for Kudu, you can customise the path but we are just going with the defaults.</p><!--kg-card-begin: markdown--><p>C:\kudu\apps<br>
C:\kudu\Kudu.Services.Web<br>
C:\kudu\wwwroot<br>
<strong>Assign IIS_IUSRS full control for</strong> C:\kudu\</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>From the S100 archive copy the contents from:<br>
\KuduWeb to C:\kudu\wwwroot<br>
\SiteExtensions\Kudu to C:\kudu\Kudu.Services.Web<br>
The apps dir is where new sites will be created.<br>
You should have a structure like</p>
<pre><code>C:\kudu
├───apps
├───Kudu.Services.Web
│   │   commit.txt
│   │   Default.cshtml
│   │   Env.cshtml
│   │   favicon.ico
│   │   package-lock.json
│   │   package.json
│   │   scmApplicationHost.xdt
│   │   updateNodeModules.cmd
│   │   Web.config
│   │   WebHooks.cshtml
│   │   _Layout.cshtml
│   ├───bin
│   ├───Content
│   ├───DebugConsole
│   ├───Detectors
│   ├───node_modules
│   ├───ProcessExplorer
│   ├───SiteExtensions
│   ├───Support
│   └───ZipDeployUI
└───wwwroot
    │   Global.asax
    │   packages.config
    │   Web.config
    ├───App_Data
    ├───bin
    ├───Content
    ├───fonts
    ├───images
    ├───Scripts
    └───Views
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>The script for updateNodeModules.cmd which will create the node_modules dir under Kudu.Services.Web</p>
<pre><code>@echo off
setlocal enabledelayedexpansion

pushd %1

set attempts=5
set counter=0

:retry
set /a counter+=1
echo Attempt %counter% out of %attempts%

cmd /c npm install https://github.com/projectkudu/KuduScript/tarball/aadbe2bd33543483dd9659d35fc591a992e7aa6f
IF %ERRORLEVEL% NEQ 0 goto error

goto end

:error
if %counter% GEQ %attempts% goto :lastError
goto retry

:lastError
popd
echo An error has occurred during npm install.
exit /b 1

:end
popd
echo Finished successfully.
exit /b 0
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Now to tweak the web.config files. You can read the <a href="https://github.com/projectkudu/kudu/wiki">wiki</a> to know what these configs do as they're not there by default</p>
<p><code>C:\kudu\Kudu.Services.Web\web.config</code></p>
<pre><code>  &lt;appSettings&gt;
    &lt;add key=&quot;SCM_SKIP_SSL_VALIDATION&quot; value=&quot;1&quot; /&gt;
    &lt;add key=&quot;SCM_TRACE_LEVEL&quot; value=&quot;4&quot; /&gt;
    &lt;add key=&quot;SCM_NO_REPOSITORY&quot; value=&quot;1&quot; /&gt;
    &lt;add key=&quot;SCM_DO_BUILD_DURING_DEPLOYMENT&quot; value=&quot;0&quot; /&gt;
    &lt;add key=&quot;WEBSITE_DISABLE_SCM_SEPARATION&quot; value=&quot;1&quot; /&gt; 
    &lt;add key=&quot;WEBJOBS_HISTORY_SIZE&quot; value=&quot;100&quot; /&gt; 
    
    &lt;add key=&quot;webpages:Version&quot; value=&quot;3.0.0.0&quot; /&gt;
    &lt;add key=&quot;webpages:Enabled&quot; value=&quot;true&quot; /&gt;
    &lt;add key=&quot;webactivator:assembliesToScan&quot; value=&quot;Kudu.Services.Web&quot; /&gt;
  &lt;/appSettings&gt;
</code></pre>
<p><code>C:\kudu\wwwroot\web.config</code></p>
<pre><code>  &lt;kudu.management enableCustomHostNames=&quot;true&quot;&gt;
    &lt;serviceSite path=&quot;..\Kudu.Services.Web&quot; /&gt;
    &lt;applications path=&quot;..\apps&quot; /&gt;
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Time to create Kudu's admin app pool in IIS.<br>
Note the identity is LocalSystem and recycling has been 'disabled' so that aspects like Web Jobs can run without issues based on your cron config.<br>
<img src="https://blog.lionelchetty.dev/content/images/2025/04/004.jpg" alt="Using Kudu Outside Azure"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>After the app pool is created, we need to create the website.<br>
The physical path being <code>C:\kudu\wwwroot</code>, you can bind a random port on localhost<br>
<img src="https://blog.lionelchetty.dev/content/images/2025/04/001.jpg" alt="Using Kudu Outside Azure"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Afterwards we can browse to kudu-admin to create an app.<br>
<img src="https://blog.lionelchetty.dev/content/images/2025/04/002.jpg" alt="Using Kudu Outside Azure"><br>
<img src="https://blog.lionelchetty.dev/content/images/2025/04/003.jpg" alt="Using Kudu Outside Azure"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Kudu when creating an app will create the website and the scm aspect.<br>
website =&gt; contoso.azurewebsites.net<br>
website kudu =&gt; contoso.scm.azurewebsites.net<br>
These settings such as site bindings(DNS) if added will reflect in IIS Manager.<br>
<img src="https://blog.lionelchetty.dev/content/images/2025/04/005.jpg" alt="Using Kudu Outside Azure"><br>
<img src="https://blog.lionelchetty.dev/content/images/2025/04/006.jpg" alt="Using Kudu Outside Azure"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>website<br>
<img src="https://blog.lionelchetty.dev/content/images/2025/04/007.jpg" alt="Using Kudu Outside Azure"><br>
website-scm(Kudu)<br>
<img src="https://blog.lionelchetty.dev/content/images/2025/04/008.jpg" alt="Using Kudu Outside Azure"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Apps are created using ApplicationPoolIdentity. Now the choice is yours, if you don't want the typical features of Kudu like access to the file system to drag &amp; drop files, executing commandline/powershell scripts etc. Then you're good to go otherwise hence the creation of the 'admin' app. The app pool just needs to be set to kudu-admin which we initally created with LocalSystem privileges.<br>
<strong>Remember Kudu has no authentication or authorisation, that's handled by the Azure layer in-front of it.</strong><br>
<img src="https://blog.lionelchetty.dev/content/images/2025/04/009.jpg" alt="Using Kudu Outside Azure"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>The debug console is awesome but if the clicking is too much, you can quickly navigate the virtual file system by using the console in your browser's dev tools.</p>
<pre><code>var v = viewModel.selected();
v.href = 'https://scm-kudu.local/api/vfs/SystemDrive/Windows/system32/drivers/etc/';
updateSelectedAndNotifyCommandLine(v);
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Site extensions also work. Like if you have the iis-node module enabled, you can use something like the Monaco Editor. Since that's not publically available I can't share it so just download the source from your Azure Web App &amp; you'll figure it out.<br>
<img src="https://blog.lionelchetty.dev/content/images/2025/04/010.jpg" alt="Using Kudu Outside Azure"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>And yes, since Functions are an evolution of Web Jobs, they can also be run outside of Azure but that's a post for another time.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: embed--><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/858380944?app_id=122963" width="240" height="426" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media" title="Azure Functions without Azure"></iframe></figure><!--kg-card-end: embed-->]]></content:encoded></item><item><title><![CDATA[Security Keys for Apple ID]]></title><description><![CDATA[<p>Starting with iOS 16.3 &amp; iPadOS 16.3 comes support for <a href="https://support.apple.com/en-my/HT213154">Security Keys for Apple ID</a>, the gist is you will need two keys to get started.</p><!--kg-card-begin: markdown--><p><img src="https://blog.lionelchetty.dev/content/images/2023/01/IMG_0005-1.jpg" alt></p>
<!--kg-card-end: markdown--><!--kg-card-begin: gallery--><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2023/01/IMG_0006.jpeg" width="2360" height="1640"></div><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2023/01/IMG_0007.jpeg" width="2360" height="1640"></div></div></div></figure><!--kg-card-end: gallery--><!--kg-card-begin: markdown--><p>Weirdly my one key was treated like an HID input device so I had to toggle the on-screen keyboard to input the</p>]]></description><link>https://blog.lionelchetty.dev/security-keys-for-apple-id/</link><guid isPermaLink="false">63d719dc760898382c31f30b</guid><category><![CDATA[Apple]]></category><category><![CDATA[InfoSec]]></category><category><![CDATA[FIDO]]></category><category><![CDATA[Yubico]]></category><dc:creator><![CDATA[Lionel Christopher Chetty]]></dc:creator><pubDate>Mon, 30 Jan 2023 01:27:41 GMT</pubDate><media:content url="https://blog.lionelchetty.dev/content/images/2023/01/security-keys-for-apple-id-background-compressor.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.lionelchetty.dev/content/images/2023/01/security-keys-for-apple-id-background-compressor.jpg" alt="Security Keys for Apple ID"><p>Starting with iOS 16.3 &amp; iPadOS 16.3 comes support for <a href="https://support.apple.com/en-my/HT213154">Security Keys for Apple ID</a>, the gist is you will need two keys to get started.</p><!--kg-card-begin: markdown--><p><img src="https://blog.lionelchetty.dev/content/images/2023/01/IMG_0005-1.jpg" alt="Security Keys for Apple ID"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: gallery--><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2023/01/IMG_0006.jpeg" width="2360" height="1640" alt="Security Keys for Apple ID"></div><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2023/01/IMG_0007.jpeg" width="2360" height="1640" alt="Security Keys for Apple ID"></div></div></div></figure><!--kg-card-end: gallery--><!--kg-card-begin: markdown--><p>Weirdly my one key was treated like an HID input device so I had to toggle the on-screen keyboard to input the PIN.<br>
<img src="https://blog.lionelchetty.dev/content/images/2023/01/IMG_0011.jpeg" alt="Security Keys for Apple ID"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: gallery--><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2023/01/IMG_0012.jpeg" width="2360" height="1640" alt="Security Keys for Apple ID"></div><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2023/01/IMG_0013.jpeg" width="2360" height="1640" alt="Security Keys for Apple ID"></div></div></div></figure><!--kg-card-end: gallery-->]]></content:encoded></item><item><title><![CDATA[Tinkering with Apple MapKit JS]]></title><description><![CDATA[<p>I don't normally keep up with news from WWDC, neither does Apple normally release technology for web developers. If you use DuckDuckGo then you're probably familiar with MapKit JS, the <a href="https://developer.apple.com/maps/web/">feature set</a> available covers the needs of most.<br>If you do NOT already have access to the Apple Developer Program,</p>]]></description><link>https://blog.lionelchetty.dev/tinkering-with-apple-mapkit-js/</link><guid isPermaLink="false">6187f94685290c37b801cee0</guid><category><![CDATA[Apple]]></category><category><![CDATA[MapKit]]></category><category><![CDATA[Getting Started]]></category><dc:creator><![CDATA[Lionel Christopher Chetty]]></dc:creator><pubDate>Sun, 07 Nov 2021 20:06:59 GMT</pubDate><media:content url="https://blog.lionelchetty.dev/content/images/2021/11/apple-mapkit-js-background-compressor.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.lionelchetty.dev/content/images/2021/11/apple-mapkit-js-background-compressor.jpg" alt="Tinkering with Apple MapKit JS"><p>I don't normally keep up with news from WWDC, neither does Apple normally release technology for web developers. If you use DuckDuckGo then you're probably familiar with MapKit JS, the <a href="https://developer.apple.com/maps/web/">feature set</a> available covers the needs of most.<br>If you do NOT already have access to the Apple Developer Program, this post is probably not for you.</p><!--kg-card-begin: markdown--><p>When compared to Google Maps or HERE WeGo(HERE Maps), Apple's take on this is quite refreshing.<br>
MapKit JS provides for free:</p>
<ul>
<li>250,000 map views</li>
<li>25,000 service calls</li>
<li>25,000 Snapshots unique requests</li>
</ul>
<p><strong>These limits are PER day!</strong></p>
<p><img src="https://blog.lionelchetty.dev/content/images/2021/11/maps.developer.apple.com-compressor.jpeg" alt="Tinkering with Apple MapKit JS"></p>
<p>Similar to unlimited OneDrive storage, when you get close to the limit, you can request your limits be increased.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Apple emphasises <em>on the web</em>, the setup is simple.<br>
You craft a JWT like so</p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><script src="https://gist.github.com/dalion619/6e58903230be7a3484f27746e5457d85.js"></script><!--kg-card-end: html--><!--kg-card-begin: markdown--><p>Sign the JWT with your private key, pass it to the MapKit JS library which bootstaps everything and retrieves an access token.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><script src="https://gist.github.com/dalion619/c77fb32ffb8fac40ae395f728bb5cf77.js"></script><!--kg-card-end: html--><!--kg-card-begin: markdown--><p><a href="https://github.com/adam-russell">Adam Russell</a> has a detailed <a href="https://www.adamrussell.com/mapkit-js-with-asp-net-core/">post on how to get that setup on ASP.NET Core.</a></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>If you want to generate snapshot urls or reverse geocode on the backend then you'll find Apple's documentation sparse on the required endpoints and how to use them.<br>
I have a basic C# project on <a href="https://github.com/dalion619/apple-mapkit-dotnet">GitHub</a> as an example of performing such tasks with those undocumented endpoints.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Using the Microsoft Graph to manage files in OneDrive/SharePoint like Azure Blob Storage]]></title><description><![CDATA[<p>When compared to Azure Blob Storage, SharePoint/OneDrive for Business is much more cost effective, but it is important to note I am NOT doing a 1:1 on the features offered. You might want a fixed cost for the storing/accessing data or the sharing abilities of SharePoint or</p>]]></description><link>https://blog.lionelchetty.dev/using-the-microsoft-graph-to-manage-files-in-onedrivesharepoint-like-azure-blob-storage/</link><guid isPermaLink="false">5f133b7171f537b16c143121</guid><category><![CDATA[Azure]]></category><category><![CDATA[Azure AD]]></category><category><![CDATA[Microsoft]]></category><category><![CDATA[Microsoft Graph]]></category><category><![CDATA[SharePoint]]></category><category><![CDATA[OneDrive]]></category><category><![CDATA[Getting Started]]></category><dc:creator><![CDATA[Lionel Christopher Chetty]]></dc:creator><pubDate>Sun, 19 Jul 2020 13:55:26 GMT</pubDate><media:content url="https://blog.lionelchetty.dev/content/images/2020/07/microsoft-graph-365-background-compressor-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.lionelchetty.dev/content/images/2020/07/microsoft-graph-365-background-compressor-1.jpg" alt="Using the Microsoft Graph to manage files in OneDrive/SharePoint like Azure Blob Storage"><p>When compared to Azure Blob Storage, SharePoint/OneDrive for Business is much more cost effective, but it is important to note I am NOT doing a 1:1 on the features offered. You might want a fixed cost for the storing/accessing data or the sharing abilities of SharePoint or the sync features of OneDrive, for whichever reason Microsoft 365 Business makes sense.</p><!--kg-card-begin: markdown--><p>You can even try it out for free, by joining the <a href="https://developer.microsoft.com/office/profile">Microsoft 365 Developer Program</a>.<br>
You get a Microsoft 365 E5 developer subscription, with</p>
<blockquote>
<p>25 user licenses for development purposes<br>
Access core Microsoft 365 workloads and capabilities (Windows not included), including:<br>
All Office 365 apps including SharePoint, OneDrive, Outlook/Exchange, Teams, Planner, Word, Excel, PowerPoint, and more<br>
Office 365 Advanced Threat Protection<br>
Advanced analytics with Power BI<br>
Enterprise Mobility + Security (EMS) for compliance and information protection<br>
Azure Active Directory for building advanced identity and access management solutions</p>
</blockquote>
<p><img src="https://blog.lionelchetty.dev/content/images/2020/07/00.-Dashboard---Microsoft-365-Dev-Center-compressor.png" alt="Using the Microsoft Graph to manage files in OneDrive/SharePoint like Azure Blob Storage"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Before you can play around with the Microsoft Graph, you need to register an App under your tenant. To set this up, go to <a href="https://portal.azure.com/">https://portal.azure.com/</a><br>
Browse to <strong>Azure Active Directory</strong>, click on the <strong>App registrations</strong> blade then click on <strong>New registration</strong>.<br>
For <strong>Redirect Uri</strong> use <code>https://localhost:8080/</code></p>
<p><img src="https://blog.lionelchetty.dev/content/images/2020/07/01.-Register-an-application---Azure-AD-compressor.png" alt="Using the Microsoft Graph to manage files in OneDrive/SharePoint like Azure Blob Storage"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>After creating your app, click on the <strong>API permissions</strong> blade then click on <strong>Add a permission</strong>, select <strong>Microsoft Graph</strong> then choose <strong>Application permissions</strong>. In this example, tick <strong>Group.ReadWrite.All</strong>.</p>
<p><img src="https://blog.lionelchetty.dev/content/images/2020/07/02.Request-API-permissions---Azure-AD-App-compressor.png" alt="Using the Microsoft Graph to manage files in OneDrive/SharePoint like Azure Blob Storage"><br>
<img src="https://blog.lionelchetty.dev/content/images/2020/07/03.API-permissions---Azure-AD-App-compressor.png" alt="Using the Microsoft Graph to manage files in OneDrive/SharePoint like Azure Blob Storage"></p>
<p>Next click <strong>Grant admin consent</strong>.</p>
<p><img src="https://blog.lionelchetty.dev/content/images/2020/07/04.Grant-API-permissions---Azure-AD-App-compressor.png" alt="Using the Microsoft Graph to manage files in OneDrive/SharePoint like Azure Blob Storage"><br>
<img src="https://blog.lionelchetty.dev/content/images/2020/07/05.Granted-API-permissions---Azure-AD-App-compressor.png" alt="Using the Microsoft Graph to manage files in OneDrive/SharePoint like Azure Blob Storage"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Now click on the <strong>Certificates &amp; secrets</strong> blade then click on <strong>New client secret</strong> and add a secret.</p>
<p><img src="https://blog.lionelchetty.dev/content/images/2020/07/06.-Secrets---Azure-AD-App-compressor.png" alt="Using the Microsoft Graph to manage files in OneDrive/SharePoint like Azure Blob Storage"><br>
<img src="https://blog.lionelchetty.dev/content/images/2020/07/07.-New-Secret---Azure-AD-App-compressor.png" alt="Using the Microsoft Graph to manage files in OneDrive/SharePoint like Azure Blob Storage"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>That is about it! If you want an example of implementing the API to upload and download files, I have a basic C# project on <a href="https://github.com/dalion619/investec-openbanking-dotnet/tree/master/examples/MicrosoftGraph.RestClient">GitHub</a>.</p>
<p>If you're unsure what permissions are required by each endpoint, I suggest using the <a href="https://developer.microsoft.com/en-us/graph/graph-explorer">Microsoft Graph Explorer</a> to find out.<br>
<img src="https://blog.lionelchetty.dev/content/images/2020/07/Graph-Explorer---Microsoft-Graph-compressor.png" alt="Using the Microsoft Graph to manage files in OneDrive/SharePoint like Azure Blob Storage"></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Using Cloudflare's WARP VPN on Windows]]></title><description><![CDATA[WARP is a VPN solution from Cloudflare built on the WireGuard protocol. Its goal to keep your internet experience private, secure, fast and reliable. ]]></description><link>https://blog.lionelchetty.dev/using-cloudflares-warp-vpn-on-windows/</link><guid isPermaLink="false">5e7f91ecd0d2884e145baba4</guid><category><![CDATA[Cloudflare]]></category><category><![CDATA[WARP]]></category><category><![CDATA[VPN]]></category><category><![CDATA[1.1.1.1]]></category><dc:creator><![CDATA[Lionel Christopher Chetty]]></dc:creator><pubDate>Sun, 29 Mar 2020 04:21:44 GMT</pubDate><media:content url="https://blog.lionelchetty.dev/content/images/2020/03/cloudflare-warp-github-background-compressor.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.lionelchetty.dev/content/images/2020/03/cloudflare-warp-github-background-compressor.jpg" alt="Using Cloudflare's WARP VPN on Windows"><p><a href="https://warp.plus/">WARP</a> is a VPN solution from Cloudflare built on the WireGuard protocol. Its goal to keep your internet experience private, secure, fast and reliable. </p><p>It's free to use on <a href="https://play.google.com/store/apps/details?id=com.cloudflare.onedotonedotonedotone">Android</a> and <a href="https://itunes.apple.com/us/app/1-1-1-1-faster-internet/id1423538627">iOS</a>, the premium version WARP+ is powered by <a href="https://www.cloudflare.com/products/argo-smart-routing/">Argo Smart Routing</a>. Let's set it up on Windows.</p><!--kg-card-begin: markdown--><h3 id="creatingawarpaccount">Creating a WARP Account</h3>
<p>If you have a rooted Android device, awesome. If not download <a href="https://www.memuplay.com">MEmu</a>. This is the easiest emulator to get going that's rooted with Google Play Services. Trust me, I wasted a lot of time trying the others.</p>
<p>Download the <a href="https://play.google.com/store/apps/details?id=com.cloudflare.onedotonedotonedotone">1.1.1.1 app</a> and follow the prompts, at this point I recommend signing up for WARP+ at R30 a month.<br>
<img src="https://blog.lionelchetty.dev/content/images/2020/03/MEmu_Screenshot_2020-01-19-10-19-53-compressor.png" alt="Using Cloudflare's WARP VPN on Windows"></p>
<p>Once you have your account, copy the <strong>com.cloudflare.onedotonedotonedotone</strong> folder to your PC, <a href="https://www.memuplay.com/blog/how-to-share-files-between-windows-and-android.html">here's a guide on how to do this</a>.<br>
<img src="https://blog.lionelchetty.dev/content/images/2020/03/MEmu_Screenshot_2020-01-19-10-26-23-compressor.png" alt="Using Cloudflare's WARP VPN on Windows"></p>
<p>Once you have the folder, in the <strong>shared_prefs</strong> directory, <em>com.cloudflare.onedotonedotonedotonepreferences.xml</em> is the file you're after. This has your account details, with it you can use any WireGuard VPN Client.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><script src="https://gist.github.com/dalion619/53b03fe62c2202297ae03831d0486720.js"></script><!--kg-card-end: html--><!--kg-card-begin: markdown--><h3 id="wireguardvpnclient">WireGuard VPN Client</h3>
<p>If you made it here, so far so good. I use <a href="https://tunsafe.com/">TunSafe</a> as my client. You'll need to provide a config file, here's an example based on the values from the XML.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><script src="https://gist.github.com/dalion619/08b80408254edf684f40ca405d5c7c9e.js"></script><!--kg-card-end: html--><!--kg-card-begin: markdown--><h3 id="multideviceuse">Multi-Device Use</h3>
<p>In the last two weeks or with the app update to v5, Cloudflare introduced the account ability to link your profile with 5 devices. This is done with the use of a license key, it's cross platform so you can mix Android and iOS.<br>
<img src="https://blog.lionelchetty.dev/content/images/2020/03/CLoudflare-WARP--iOS-compressor.jpg" alt="Using Cloudflare's WARP VPN on Windows"></p>
<p>If you're like me and have had WARP+ for a while and now you're wondering how do you get your license key? Simple, there's an API for that, replace {value} with your values from that same original XML file.</p>
<pre><code>GET /v0a833/reg/{warp_registration_id} HTTP/1.1
Host: api.cloudflareclient.com
Authorization: Bearer {warp_token}
Content-Type: application/json; charset=UTF-8
User-Agent: okhttp/3.12.1
Content-Type: application/json
</code></pre>
<p>You'll get a response similar to this.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><script src="https://gist.github.com/dalion619/2bfa05fdf66ad35a4d758cc750969f9a.js"></script><!--kg-card-end: html--><!--kg-card-begin: markdown--><h3 id="whenwindowsgivesyoulinuxbinaries">When Windows gives you Linux binaries</h3>
<p>MTR</p>
<pre><code>Host                               Loss%   Snt   Last    Avg   Best  Wrst  StDev

Non-WARP+
1. LIONEL-YOGA920 (172.29.16.1)    0.0%    25     0.4    0.5     0.3   1.4   0.2
2. 192.168.8.1 (192.168.8.1)       0.0%    25     3.1    3.9     2.3  11.0   2.2
3. ???
4. 105-187-234-178.telkomsa.net    0.0%    25    31.2   22.7    14.9  33.5   6.1
5. 105-187-253-58.telkomsa.net     0.0%    25    17.4   18.8    15.1  25.7   2.9
6. 105-187-234-93.telkomsa.net     0.0%    25    22.7   22.5    17.8  43.2   6.0
7. rrba-os-cer-1-wan.osnet.co.za   0.0%    25    19.7   24.3    17.9  39.4   6.3
8. 10.189.30.6 (10.189.30.6)       0.0%    25   227.0  226.6   217.0 237.7   5.1
9. (149.14.126.225)                5.3%    25   223.6  225.8   213.9 235.0   5.7
10. mei-b3-link.telia.net          5.3%    25   238.8  232.0   219.3 264.5  11.8
11. ffm-bb2-link.telia.net         5.3%    25   254.4  247.4   242.0 262.7   5.3
12. ffm-b1-link.telia.net          0.0%    25   260.7  248.1   232.6 272.7   9.0
13. (62.115.182.171)               0.0%    25   247.8  252.7   237.7 296.2  14.1
14. ???
15. ???
16. ams.github.com (140.82.118.4)  0.0%    25   248.2  253.8   243.2 276.4   8.2

 
WARP+ 
1. LIONEL-YOGA920 (172.29.16.1)    0.0%    25     0.4    0.4     0.2   0.7   0.1
2. 172.16.0.1 (172.16.0.1)         0.0%    25    26.4   32.1    16.7  79.6  13.1
3. 197.234.241.1 (197.234.241.1)   0.0%    25    25.9   32.5    19.1  86.5  14.2
4. 105.22.32.217 (105.22.32.217)   0.0%    25    17.8   43.2    15.5 115.8  23.6
5. 105.16.28.1 (105.16.28.1)       0.0%    25   190.0  193.2   178.1 221.0  11.0
6. 105.16.10.214 (105.16.10.214)   0.0%    25   198.2  191.9   176.4 209.8   6.8
7. 105.16.14.189 (105.16.14.189)   0.0%    25   179.8  188.2   177.9 203.7   6.8
8. 105.16.33.253 (105.16.33.253)   0.0%    25   183.8  188.7   176.2 241.2  14.6
9. 92.60.248.233 (92.60.248.233)   0.0%    25   177.8  191.8   177.8 269.4  20.3
10. 89.149.184.33 (89.149.184.33)  0.0%    25   200.7  216.4   190.6 306.0  37.0
11. 87.119.94.70 (87.119.94.70)    0.0%    25   212.7  225.3   201.0 349.8  36.3
12. ???
13. ???
14. 140.82.118.3 (140.82.118.3)    0.0%    25   204.9  208.9   195.5 250.6  12.9
</code></pre>
<p>Also good old Speedtest.</p>
<p><a href="https://www.speedtest.net/result/i/3782118389"><img src="https://www.speedtest.net/result/i/3782118389.png" alt="Using Cloudflare's WARP VPN on Windows"></a><br>
<a href="https://www.speedtest.net/result/i/3782120531"><img src="https://www.speedtest.net/result/i/3782120531.png" alt="Using Cloudflare's WARP VPN on Windows"></a><br>
<a href="https://www.speedtest.net/result/i/3782123231"><img src="https://www.speedtest.net/result/i/3782123231.png" alt="Using Cloudflare's WARP VPN on Windows"></a><br>
<a href="https://www.speedtest.net/result/i/3782124961"><img src="https://www.speedtest.net/result/i/3782124961.png" alt="Using Cloudflare's WARP VPN on Windows"></a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Adding ReSharper code analysis to your Azure DevOps CI build pipeline]]></title><description><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p><a href="https://www.jetbrains.com/help/resharper/ReSharper_Command_Line_Tools.html">ReSharper Command Line Tools</a> is a set of free cross-platform standalone tools that help you integrate automatic code quality analysis into your CI, version control or any other server.</p>
</blockquote>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><a href="https://www.jetbrains.com/resharper/download/index.html#section=commandline">The Command Line Tools package</a> includes the following tools:</p>
<ul>
<li>InspectCode, which executes hundreds of ReSharper code inspections</li>
<li>DupFinder, which detects duplicated</li></ul>]]></description><link>https://blog.lionelchetty.dev/adding-resharper-code-analysis-to-you/</link><guid isPermaLink="false">5e36c0d19ab67b1ad4d81e6c</guid><category><![CDATA[Azure]]></category><category><![CDATA[Azure DevOps]]></category><category><![CDATA[JetBrains]]></category><category><![CDATA[ReSharper]]></category><category><![CDATA[Code]]></category><category><![CDATA[Code Analysis]]></category><dc:creator><![CDATA[Lionel Christopher Chetty]]></dc:creator><pubDate>Sun, 02 Feb 2020 22:00:06 GMT</pubDate><media:content url="https://blog.lionelchetty.dev/content/images/2020/02/ci-code-analysis-background-compressor.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<img src="https://blog.lionelchetty.dev/content/images/2020/02/ci-code-analysis-background-compressor.jpg" alt="Adding ReSharper code analysis to your Azure DevOps CI build pipeline"><p><a href="https://www.jetbrains.com/help/resharper/ReSharper_Command_Line_Tools.html">ReSharper Command Line Tools</a> is a set of free cross-platform standalone tools that help you integrate automatic code quality analysis into your CI, version control or any other server.</p>
</blockquote>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><a href="https://www.jetbrains.com/resharper/download/index.html#section=commandline">The Command Line Tools package</a> includes the following tools:</p>
<ul>
<li>InspectCode, which executes hundreds of ReSharper code inspections</li>
<li>DupFinder, which detects duplicated code in the whole solution or narrower scope</li>
<li>CleanupCode, which instantly eliminates code style violations and ensures a uniform code base</li>
</ul>
<!--kg-card-end: markdown--><p>I'll only be covering InspectCode and DupFinder,  I had some issues with the latest version (2019.3) so I'm using 2019.2.4</p><p>For this guide, we're using a basic build pipeline running on a hosted agent. <br>The tasks include:</p><ul><li>Fetching code from the Git repo</li><li>Restoring dependencies with Nuget </li><li>Fetching the ReSharper CLT and invoking it with PowerShell</li><li>Publishing the outputs</li></ul><!--kg-card-begin: image--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lionelchetty.dev/content/images/2020/02/Compare-The-Store-CI---Azure-DevOps-Services.png" class="kg-image" alt="Adding ReSharper code analysis to your Azure DevOps CI build pipeline"><figcaption>Azure DevOps build pipeline</figcaption></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><h2 id="powershelltasks">PowerShell Tasks</h2>
<p>The tasks below are guidelines, adapt to your needs/context.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="fetchingtheresharpercommandlinetools">Fetching the ReSharper Command Line Tools</h3>
<p>You can store the ReSharper CLT wherever you wish. Your repo, Azure Blob Storage but for this example I used GitHub.</p>
<p>Downloading the repo as a zip file is easy enough.<br>
<img src="https://blog.lionelchetty.dev/content/images/2020/02/Compare-The-Store-CI---PowerShell-Task-1-compressor.png" alt="Adding ReSharper code analysis to your Azure DevOps CI build pipeline"></p>
<pre><code>Invoke-WebRequest &quot;https://github.com/dalion619/jetbrains-resharper-clt/archive/master.zip&quot; -OutFile &quot;.\jb-clt.zip&quot;
</code></pre>
<p>Then extracting it into the current working directory.</p>
<pre><code>Expand-Archive &quot;.\jb-clt.zip&quot; -DestinationPath &quot;.\&quot; -Force
</code></pre>
<p>The end result being.</p>
<pre><code>$Env:BUILD_SOURCESDIRECTORY\jetbrains-resharper-clt-master\
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>I wrote a bad PowerShell script to help to with invoking DupFinder and InspectCode.<br>
It takes 3 parameters:</p>
<ul>
<li>$SolutionFilePath, path to solution file. This is required.</li>
<li>$OutputDirPath, path to directory for saving the reports.<br>
Default value = '..\output'</li>
<li>$ExcludedExtensions, comma-separated values of the file extensions to exclude from analysis.<br>
Default value ='js,css'</li>
</ul>
<p>Exclusions work with a DotSettings file, which is a ReSharper/Rider file but the script will create it for you.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><script src="https://gist.github.com/dalion619/523258ac31f48297bcc52437d3a78ec8.js"></script><!--kg-card-end: html--><!--kg-card-begin: markdown--><h3 id="invokingdupfinderandinspectcode">Invoking DupFinder and InspectCode</h3>
<p>The important part here is, setting the working directory because we're using relative paths.</p>
<pre><code>.\jetbrains-resharper-clt-master\
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: gallery--><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2020/02/Screenshot_2020-02-02-Compare-The-Store-CI-DupFinder-compressor-1.png" width="1998" height="1574" alt="Adding ReSharper code analysis to your Azure DevOps CI build pipeline"></div><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2020/02/Screenshot_2020-02-02-Compare-The-Store-CI-InspectCode-compressor-1.png" width="1998" height="1574" alt="Adding ReSharper code analysis to your Azure DevOps CI build pipeline"></div></div></div><figcaption>PowerShell Code Analysis Tasks</figcaption></figure><!--kg-card-end: gallery--><!--kg-card-begin: markdown--><p>Calling Publish-DupFinder-Analysis or Publish-InspectCode-Analysis will create the respective analysis report.</p>
<p>By default the reports are created in XML, but I modified the XSLT templates to include some Bulma CSS so the HTML versions look nicer.</p>
<p>You then can go upload the reports as an Artifact or upload them to Azure Blob Storage.<br>
<img src="https://blog.lionelchetty.dev/content/images/2020/02/Screenshot_2020-02-02-275-Compare-The-Store-CI-Artifact-compressor.png" alt="Adding ReSharper code analysis to your Azure DevOps CI build pipeline"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lionelchetty.dev/content/images/2020/02/ReSharper-DupFinder-Report-compressor.png" class="kg-image" alt="Adding ReSharper code analysis to your Azure DevOps CI build pipeline"><figcaption>DupFinder Report</figcaption></figure><!--kg-card-end: image--><!--kg-card-begin: gallery--><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2020/02/ReSharper-InspectCode-Report-compressor.png" width="3806" height="1836" alt="Adding ReSharper code analysis to your Azure DevOps CI build pipeline"></div><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2020/02/Code-Inspection--Use-preferred-body-style--convert-to-property--indexer-or-event-with-preferred-body-style----Help---ReSharper-compressor-1.png" width="3840" height="1836" alt="Adding ReSharper code analysis to your Azure DevOps CI build pipeline"></div></div></div><figcaption>InspectCode Report</figcaption></figure><!--kg-card-end: gallery-->]]></content:encoded></item><item><title><![CDATA[Killing passwords with YubiKey and Microsoft]]></title><description><![CDATA[Enabling passwordless sign-in on your Microsoft Account(MSA) or Azure Active Directory(AAD) account. Understanding FIDO2 and how Yubico's Security Key(YubiKey) and Windows Hello tie into the process.]]></description><link>https://blog.lionelchetty.dev/killing-passwords-with-yubikey-and-microsoft/</link><guid isPermaLink="false">5d2ee5cca46978345049a376</guid><category><![CDATA[YubiKey]]></category><category><![CDATA[Yubico]]></category><category><![CDATA[Microsoft]]></category><category><![CDATA[Azure]]></category><category><![CDATA[Azure AD]]></category><category><![CDATA[Active Directory]]></category><category><![CDATA[InfoSec]]></category><category><![CDATA[Passwordless]]></category><category><![CDATA[Windows Hello]]></category><category><![CDATA[Security Key]]></category><category><![CDATA[MFA]]></category><category><![CDATA[2FA]]></category><category><![CDATA[2SV]]></category><category><![CDATA[FIDO]]></category><category><![CDATA[FIDO2]]></category><category><![CDATA[WebAuthn]]></category><dc:creator><![CDATA[Lionel Christopher Chetty]]></dc:creator><pubDate>Tue, 23 Jul 2019 14:57:23 GMT</pubDate><media:content url="https://blog.lionelchetty.dev/content/images/2019/07/killing-passwords-background-compressor-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://blog.lionelchetty.dev/content/images/2019/07/killing-passwords-background-compressor-1.jpg" alt="Killing passwords with YubiKey and Microsoft"><p>Authentication can have multiple factors, commonly referred to as Multi-Factor Authentication (MFA), the common factors are:</p>
<ul>
<li>Knowledge: Something you know - password</li>
<li>Possession: Something you have - security token generator (device)</li>
<li>Inherence: Something you are - fingerprint (biometric)</li>
</ul>
<p>Two-step verification (2SV) is an approach of having a secondary step in confirming who you are, when the secondary method is one of the other factors then it is two-factor authentication (2FA). A code you receive via SMS isn't technically 2FA.</p>
<!--kg-card-end: markdown--><p>After that brief intro, 2FA still has some weak points like <a href="https://blog.codinghorror.com/there-is-no-longer-any-such-thing-as-computer-security/">phishing</a>. I won't be breaking down FIDO U2F, I'll skip to the evolved <a href="https://www.yubico.com/2018/05/what-is-fido2/">FIDO2</a> standard.<br>Fast IDentity Online is set of open and scalable standards for strong authentication developed by the <a href="https://fidoalliance.org/fido2/">FIDO alliance</a> whose members include Microsoft and Yubico.</p><!--kg-card-begin: markdown--><p>I'm not a fan of traveling but I have the privilege of having friends that do so I get my hands on tech that isn't easily available in South Africa. One of these endeavours lead to me, getting my hands on a Yubico Security Key.<br>
<img src="https://blog.lionelchetty.dev/content/images/2019/07/yubikey-compressor.jpg" alt="Killing passwords with YubiKey and Microsoft"></p>
<!--kg-card-end: markdown--><p>With the release of Windows 10 version 1903, Windows Hello got <a href="https://techcommunity.microsoft.com/t5/Windows-IT-Pro-Blog/Windows-Hello-FIDO2-certification-gets-you-closer-to/ba-p/534592">FIDO2 certification</a>. This means I can use FIDO2 based passwordless sign in with my Microsoft Account. Even better it's in <a href="https://techcommunity.microsoft.com/t5/Azure-Active-Directory-Identity/Announcing-the-public-preview-of-Azure-AD-support-for-FIDO2/ba-p/746362">public preview for Azure Active Directory</a>.</p><p>Below is an example of using Windows Hello to sign in passwordless to a Microsoft Account.</p><!--kg-card-begin: embed--><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/349480832?app_id=122963" width="426" height="240" frameborder="0" title="Outlook passwordless sign in" allow="autoplay; fullscreen" allowfullscreen></iframe></figure><!--kg-card-end: embed--><!--kg-card-begin: markdown--><p>To set this up, go to <a href="https://account.microsoft.com/security/">https://account.microsoft.com/security/</a><br>
<img src="https://blog.lionelchetty.dev/content/images/2019/07/01.-Microsoft-account-Security-compressor.png" alt="Killing passwords with YubiKey and Microsoft"></p>
<p>Click <strong>More security options</strong> and scroll to <strong>Windows Hello and security keys</strong><br>
<img src="https://blog.lionelchetty.dev/content/images/2019/07/02.-Additional-security-options-compressor.png" alt="Killing passwords with YubiKey and Microsoft"></p>
<p>You can manage your sign-in methods at <a href="https://account.live.com/proofs/fido/manage">https://account.live.com/proofs/fido/manage</a><br>
<img src="https://blog.lionelchetty.dev/content/images/2019/07/03.-Manage-your-sign-in-methods-compressor.png" alt="Killing passwords with YubiKey and Microsoft"></p>
<!--kg-card-end: markdown--><p>Below is an example of using a security key to sign in passwordless to an Azure AD Account.</p><!--kg-card-begin: embed--><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/349481052?app_id=122963" width="426" height="240" frameborder="0" title="Office 365 passwordless sign in" allow="autoplay; fullscreen" allowfullscreen></iframe></figure><!--kg-card-end: embed--><!--kg-card-begin: markdown--><p>To set this up, go to <a href="https://portal.azure.com/">https://portal.azure.com/</a><br>
Browse to <strong>Azure Active Directory</strong>, click on the <strong>User Settings</strong> blade then click on Manage user <strong>feature preview settings</strong><br>
<img src="https://blog.lionelchetty.dev/content/images/2019/07/01.-Users-User-settings-Azure-Active-Directory-admin-center-compressor.png" alt="Killing passwords with YubiKey and Microsoft"></p>
<p>Choose selected users or all users in your directory and save.<br>
<img src="https://blog.lionelchetty.dev/content/images/2019/07/02.-User-feature-previews-Azure-Active-Directory-admin-center-compressor.png" alt="Killing passwords with YubiKey and Microsoft"></p>
<p>Then browse to the <strong>Authentication methods</strong> blade, select the method either FIDO2 security key or Microsoft Authenticator passwordless sign-in, then choose select users or all and save.<br>
<img src="https://blog.lionelchetty.dev/content/images/2019/07/03.-Authentication-methods-Authentication-method-policy--Preview-Azure-Active-Directory-admin-center-compressor.png" alt="Killing passwords with YubiKey and Microsoft"></p>
<p>Then head to <a href="https://myprofile.microsoft.com">https://myprofile.microsoft.com</a><br>
Click <strong>Security Info</strong> and register your FIDO2 security key.<br>
<img src="https://blog.lionelchetty.dev/content/images/2019/07/04.-My-Profile-compressor.png" alt="Killing passwords with YubiKey and Microsoft"></p>
<!--kg-card-end: markdown--><p>Note although you can use the <a href="https://docs.microsoft.com/en-us/azure/active-directory/user-help/user-help-auth-app-download-install">Microsoft Authenticator app</a> with many organisations, you can only enable the passwordless sign-in option with only one organisation to which your device is registered with.<br>With security keys you don't have any limitations. If you happen to lose it, nobody will know what services your key is associated with or be able to use it without the pin.</p><p>I haven't gone down the route of enabling security keys for Windows sign-in because I use Windows Hello, but if your devices are Azure AD joined with Windows 10 version 1809, you can easily set it up via Intune.</p><p>Overall using my fingerprint to sign-in feels more intuitive and seamless, using a security key feels more natural as you would a normal key in real life. Passwordless is easily a buzzword I can get behind and support.</p>]]></content:encoded></item><item><title><![CDATA[Observations from a week with Pi-hole]]></title><description><![CDATA[My observations of Pi-hole. Its more than just an ad blocker. Learning which Pi to pick, which upstream DNS provider is best and how everything works.]]></description><link>https://blog.lionelchetty.dev/observations-from-a-week-with-pi-hole/</link><guid isPermaLink="false">5d28b5009e2ea914300c42d6</guid><category><![CDATA[Pi-hole]]></category><category><![CDATA[Cloudflare]]></category><category><![CDATA[DNS]]></category><dc:creator><![CDATA[Lionel Christopher Chetty]]></dc:creator><pubDate>Mon, 15 Jul 2019 10:14:39 GMT</pubDate><media:content url="https://blog.lionelchetty.dev/content/images/2019/07/pi-hole-background-compressor.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<img src="https://blog.lionelchetty.dev/content/images/2019/07/pi-hole-background-compressor.jpg" alt="Observations from a week with Pi-hole"><p>Pi-hole® - Network-wide Ad Blocking</p>
</blockquote>
<!--kg-card-end: markdown--><p>Basically <a href="https://pi-hole.net/">Pi-hole®</a> is an application that performs the function of being a DNS server and DHCP server if you wish for all the devices on your network. In the process it also aims to block network queries to domains in the categories of analytics, telemetry, advertisements and tracking.</p><p>The idea of trying it out had plagued me for a while, with <a href="https://blog.codinghorror.com/an-exercise-program-for-the-fat-web/">Jeff Atwood</a>, <a href="https://www.hanselman.com/blog/BlockingAdsBeforeTheyEnterYourHouseAtTheDNSLevelWithPiholeAndACheapRaspberryPi.aspx">Scott Hanselman</a> and <a href="https://www.troyhunt.com/mmm-pi-hole/">Troy Hunt</a> covering the basic setup on a Raspberry Pi.<br>But with a router that only serves two devices, my laptop and phone. I can't exactly call my home network sophisticated. So plan B was to use the office network, because the best testers are the ones that don't opt-in.</p><p>Although you can use a Raspberry Pi Zero, I felt safer having an actual ethernet port so I went ahead with a Raspberry Pi 3 Model B+ and 16GB microSD card for storage.</p><!--kg-card-begin: gallery--><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2019/07/IMG-4129-compressor-6.jpg" width="3024" height="3024" alt="Observations from a week with Pi-hole"></div><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2019/07/IMG-4133-compressor-1.jpg" width="3024" height="3024" alt="Observations from a week with Pi-hole"></div><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2019/07/IMG-4134-compressor-1.jpg" width="3024" height="3024" alt="Observations from a week with Pi-hole"></div></div></div><figcaption>Raspberry Pi 3 Model B+ Kit</figcaption></figure><!--kg-card-end: gallery--><p>Following this <a href="https://www.smarthomebeginner.com/pi-hole-tutorial-whole-home-ad-blocking/">great tutorial guide</a>, my Pi-hole was up and running in under an hour.<br>I used the Raspbian Buster with desktop image without an issue. With the goal being a #BetterInternet I naturally chose Cloudflare as my upstream DNS provider,<br><a href="https://1.1.1.1/">1.1.1.1</a> is the <a href="https://www.dnsperf.com/#!dns-resolvers,Africa">fastest DNS resolver</a>.</p><p>If you prefer a GUI like me, you probably prefer TeamViewer for remote access.<br>Here's a <a href="https://pimylifeup.com/raspberry-pi-teamviewer/">simply guide for setting it up on a Raspberry Pi</a>.</p><p>If you can't set the DNS server on your router, then you set the Pi-hole to be your DHCP server to solve this. If you're not using Pi-hole as your DHCP server, you'll see IP addresses in the client column of your query log. If you are using Pi-hole as your DHCP server, you'll see the hostname of the device.</p><!--kg-card-begin: markdown--><p>By default your Pi-hole will have the following blocklists.</p>
<pre><code>https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
https://mirror1.malwaredomains.com/files/justdomains
http://sysctl.org/cameleon/hosts
https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist
https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt
https://hosts-file.net/ad_servers.txt
</code></pre>
<p>I've added the following extra lists.</p>
<pre><code>
https://raw.githubusercontent.com/hoshsadiq/adblock-nocoin-list/master/hosts.txt
https://raw.githubusercontent.com/notracking/hosts-blocklists/master/hostnames.txt
https://raw.githubusercontent.com/notracking/hosts-blocklists/master/domains.txt
https://www.malwaredomainlist.com/hostslist/hosts.txt
https://someonewhocares.org/hosts/zero/hosts
https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&amp;mimetype=plaintext&amp;useip=0.0.0.0
https://raw.githubusercontent.com/mitchellkrogza/Badd-Boyz-Hosts/master/hosts
https://zerodot1.gitlab.io/CoinBlockerLists/hosts_browser
https://raw.githubusercontent.com/FadeMind/hosts.extras/master/UncheckyAds/hosts
https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.2o7Net/hosts
https://raw.githubusercontent.com/azet12/KADhosts/master/KADhosts.txt
https://raw.githubusercontent.com/AdAway/adaway.github.io/master/hosts.txt
https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Risk/hosts
https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/filters.txt
https://raw.githubusercontent.com/anudeepND/blacklist/master/adservers.txt
</code></pre>
<p>There are active communities on <a href="https://www.reddit.com/r/pihole/">Reddit</a> and <a href="https://discourse.pi-hole.net/">Discourse</a>. You can also find blocklists on <a href="https://github.com/topics/blocker?o=desc&amp;s=stars">GitHub</a>.</p>
<!--kg-card-end: markdown--><p>After the Pi-hole is active, you'll notice websites load much faster because of the reduced bloat.</p><!--kg-card-begin: gallery--><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2019/07/speedtest-with-ads-compressor-1.png" width="3840" height="2080" alt="Observations from a week with Pi-hole"></div><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2019/07/speedtest-with-no-ads-compressor-1.png" width="3840" height="2080" alt="Observations from a week with Pi-hole"></div></div></div><figcaption>speedtest.net comparison</figcaption></figure><!--kg-card-end: gallery--><p>After some time you'll get a sense of the amount of queries going on in your network and the percentage being blocked. Smartphones tend to be the worst offenders with analytics integrated into apps that track every event.</p><!--kg-card-begin: gallery--><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2019/07/pi-hole-time-period-compressor.png" width="2040" height="1075" alt="Observations from a week with Pi-hole"></div><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2019/07/pi-hole-total-queries-compressor.png" width="2040" height="790" alt="Observations from a week with Pi-hole"></div><div class="kg-gallery-image"><img src="https://blog.lionelchetty.dev/content/images/2019/07/pi-hole-top-blocked-domains-compressor.png" width="1020" height="1024" alt="Observations from a week with Pi-hole"></div></div></div><figcaption>Pi-hole observation</figcaption></figure><!--kg-card-end: gallery--><p>You can also tweak things, it's super simply to whitelist and blacklist domains. Although the Pi-hole will cover most of your bases, for things like YouTube's video ads you'll need to rely on <a href="https://github.com/gorhill/uBlock">uBlock Origin</a>.</p><p>This has been a fun worthwhile project but due to its low resource usage, just using a Raspberry Pi for running Pi-hole makes it very expensive so I recommend finding another secondary project like a YouTube content cache using <a href="https://wiki.squid-cache.org/ConfigExamples/DynamicContent/YouTube">Squid</a>.</p>]]></content:encoded></item></channel></rss>