<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Alexander Fadeev's Blog]]></title><description><![CDATA[Development | Cybersecurity]]></description><link>https://fadeevab.com/</link><image><url>https://fadeevab.com/favicon.png</url><title>Alexander Fadeev&apos;s Blog</title><link>https://fadeevab.com/</link></image><generator>Ghost 5.82</generator><lastBuildDate>Sun, 19 Apr 2026 11:36:42 GMT</lastBuildDate><atom:link href="https://fadeevab.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Reaching AI Limits (and Ending Up on StackOverflow Again)]]></title><description><![CDATA[Some thoughts about public data quality degradation. Contributing to the public domain for the sake of humanity?]]></description><link>https://fadeevab.com/reaching-ai-limits-and-stackoverflow-contributing/</link><guid isPermaLink="false">699b19f17eb2dd04ed0ebfe9</guid><category><![CDATA[AI]]></category><category><![CDATA[Development]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Wed, 25 Feb 2026 21:55:27 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2026/03/reaching-ai-limits-and-public-knowledge-2-1-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://fadeevab.com/content/images/2026/03/reaching-ai-limits-and-public-knowledge-2-1-1.png" alt="Reaching AI Limits (and Ending Up on StackOverflow Again)"><p>I&#x2019;ve been walking with this idea for a while: I found that it still makes sense to contribute &#x1D427;&#x1D428;&#x1D427;-&#x1D400;&#x1D408;-&#x1D420;&#x1D41E;&#x1D427;&#x1D41E;&#x1D42B;&#x1D41A;&#x1D42D;&#x1D41E;&#x1D41D; &#x1D424;&#x1D427;&#x1D428;&#x1D430;&#x1D425;&#x1D41E;&#x1D41D;&#x1D420;&#x1D41E; to the public domain, for a very simple reason &#x2013; it now works not only to help humans, but to &#x1D42D;&#x1D41E;&#x1D41A;&#x1D41C;&#x1D421; &#x1D400;&#x1D408; &#x1D42D;&#x1D421;&#x1D41A;&#x1D42D; &#x1D42C;&#x1D41E;&#x1D42B;&#x1D42F;&#x1D41E;&#x1D42C; &#x1D421;&#x1D42E;&#x1D426;&#x1D41A;&#x1D427;&#x1D42C;.</p><p>Also, it kinda overlaps with my frustration around edge cases when LLMs don&apos;t help, but rather &#x1D429;&#x1D425;&#x1D41A;&#x1D432; &quot;&#x1D41C;&#x1D428;&#x1D427;&#x1D41F;&#x1D422;&#x1D41D;&#x1D41E;&#x1D427;&#x1D42D;&#x1D425;&#x1D432; &#x1D430;&#x1D42B;&#x1D428;&#x1D427;&#x1D420;&quot;.</p><p>I use AI daily, it boosts my productivity. Until it doesn&apos;t.</p><p>Look at this trivial case: try searching the <em>&quot;<code>cast send blob</code>&quot;,</em> and you&apos;ll find <a href="https://ethereum.stackexchange.com/questions/172127/how-to-send-a-blob-via-foundrys-cast-send-blob-to-a-local-anvil-chain" rel="noreferrer">my <strong>self-answered</strong></a> StackOverflow post at the top.</p><h3 id="why-is-it-at-the-top-and-why-is-it-self-answered">Why is it at the top, and why is it self-answered?</h3><p>That post exists for a simple reason: AI failed me on a trivial edge case, wasting a few hours &#x23F3; of engineering time.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2026/02/image-2.png" class="kg-image" alt="Reaching AI Limits (and Ending Up on StackOverflow Again)" loading="lazy" width="1037" height="762" srcset="https://fadeevab.com/content/images/size/w600/2026/02/image-2.png 600w, https://fadeevab.com/content/images/size/w1000/2026/02/image-2.png 1000w, https://fadeevab.com/content/images/2026/02/image-2.png 1037w" sizes="(min-width: 720px) 720px"><figcaption><code spellcheck="false" style="white-space: pre-wrap;"><span>ethereum.stackexchange.com</span></code><span style="white-space: pre-wrap;"> is a StackOverflow for the Ethereum-related topics</span></figcaption></figure><p>Once I found a solution, I decided to contribute to public knowledge, thus posting a self-answered solution, allowing the search engine to index it and filling the &quot;knowledge gap&quot;.</p><p>But again...</p><h3 id="why-did-the-issue-appear-at-the-first-place">Why did the issue appear at the first place?</h3><p>Fast forwarding: <em><strong>Nobody asks publicly &#x2192; Nobody answers &#x2192; AI knows nothing</strong>.</em></p><p>Once the article appears publicly, Google indexes it, and it quickly appears at the top. Now, AI picks it up and even partially uses my wording.</p><h3 id="public-knowledge-is-decaying">Public Knowledge Is Decaying</h3><p>What happens is that in the current circumstances, when everybody is locked in their AI microcosms, information stops recycling through the public domain.</p><p>It&apos;s well-known that &quot;StackOverflow is dying&quot; (as for 2026), etc.</p><figure class="kg-card kg-image-card"><a href="https://www.ericholscher.com/blog/2025/jan/21/stack-overflows-decline/"><img src="https://www.ericholscher.com/_images/stack-overflows-decline_image_1.webp" class="kg-image" alt="Reaching AI Limits (and Ending Up on StackOverflow Again)" loading="lazy" width="1456" height="859"></a></figure><p>I&apos;m trying to see it differently.</p><blockquote>As the internet floods with AI-generated code, the &quot;Solved questions&quot; on StackOverflow are transitioning from &quot;Help Desk answers&quot; to <strong>&quot;Ground Truth.&quot;</strong> Human validation is becoming the premium service.</blockquote><p>(from the article here: <a href="https://gist.github.com/tanaikech/30b1fc76da0da8ff82b91af29c0c9f83">https://gist.github.com/tanaikech/30b1fc76da0da8ff82b91af29c0c9f83</a>)</p><p>The incentive to contribute to public knowledge has shifted. Now it is less like helping people directly and more like <strong>feeding future models</strong> that everyone will use.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2026/03/f1782f46-17e7-4a17-99bb-801d45ba4861-1.png" class="kg-image" alt="Reaching AI Limits (and Ending Up on StackOverflow Again)" loading="lazy" width="1536" height="1024" srcset="https://fadeevab.com/content/images/size/w600/2026/03/f1782f46-17e7-4a17-99bb-801d45ba4861-1.png 600w, https://fadeevab.com/content/images/size/w1000/2026/03/f1782f46-17e7-4a17-99bb-801d45ba4861-1.png 1000w, https://fadeevab.com/content/images/2026/03/f1782f46-17e7-4a17-99bb-801d45ba4861-1.png 1536w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Here must&apos;ve been a comment on the overall public data quality degradation, but the article ended up describing the edges of knowledge, and it&apos;s good, let it be so</span></figcaption></figure><h3 id="ai-wastes-engineering-time-at-the-edges">AI Wastes Engineering Time at the Edges</h3><ol><li>I spent<em> over an hour</em> &#x23F3; asking different LLM models from different vendors how to send a blob via the <code>cast</code> tool. All models answered confidently &#x2013; and all were wrong. They <em>invented  </em>CLI flags, <strong><em>hallucinated </em></strong>parameters, and ignored requests for up-to-date documentation. The real solution took <strong>minutes </strong>&#x23F3;: I stopped prompting and read <code>cast --help</code> carefully (and then I posted that self-answer).</li><li>The other day, a similar thing happened with <strong>LogQL</strong> (a query language for Grafana Loki). After <em>an hour or two </em>&#x23F3; of back-and-forth with AI, I gave up, opened the official docs, and composed a proper LogQL query myself.</li></ol><p>This happened to me a few times.</p><p>LLMs fail similarly at <strong>edge cases.</strong></p><h3 id="edge-cases-break-llm-reasoning">Edge Cases Break LLM Reasoning</h3><p>LLMs are trained on public texts (particularly). When edge cases aren&apos;t documented, models struggle to find correct solutions and often <em>hallucinate non-working answers overconfidently</em>.</p><p>This failure mode is kind of <em>invisible</em>. If you already know the tool or the domain well, you&apos;ll notice when the answer smells wrong and go read the docs. If you don&apos;t, you might just keep trying random variations of a hallucinated solution, assuming you&apos;re the one missing something. </p><p>That&apos;s not great, especially for less popular tools, smaller projects, or newer ecosystems. It&apos;s <strong>wastes engineering time</strong>, and it adds up. The problem isn&apos;t that the models don&apos;t know. It&apos;s that they don&apos;t signal uncertainty. The former might be fixable &#x2013; models can be taught to say &quot;I don&apos;t know&quot;. The dependency on public knowledge is a different thing, though. It&apos;s not easy to &quot;fix&quot;.</p><hr><p>The conclusion here is that both me and AI end up relying on<strong> </strong>static non-conversational <strong>public knowledge</strong>.</p><p>In a way, this brings us back to a familiar place:<em> contributing to public knowledge suddenly matters.</em> It feels like contributing to the public domain matters not only to humans but also to AI serving humans.</p>]]></content:encoded></item><item><title><![CDATA[Rust GOes Async]]></title><description><![CDATA[I found a quite helpful way to get a better feeling of async Rust by looking at it from the Go perspective.]]></description><link>https://fadeevab.com/rust-goes-async/</link><guid isPermaLink="false">67702ca6999a550535a422b8</guid><category><![CDATA[Development]]></category><category><![CDATA[Rust]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Sun, 29 Dec 2024 01:56:43 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2024/12/rust-vs-go-wide.png" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->
<img src="https://fadeevab.com/content/images/2024/12/rust-vs-go-wide.png" alt="Rust GOes Async"><p style="text-align: center;">&#x295;&#x25D4;&#x3D6;&#x25D4;&#x294; <code>go f(x)</code> = <code>spawn(f(x))</code> &#x1F980;</p>
<!--kg-card-end: html-->
<p>I had a backend project of a microservice that needed to be implemented with asynchronous Rust. At that time, there was a similar Go project, so I kinda got the chance to look at async Rust through the lens of Go&apos;s approach.</p><p>There is something cozy about Go&apos;s goroutines: you just use the <code>go</code> keyword, and it magically runs a function concurrently on a lightweight &quot;green thread&quot;.</p><p>Meanwhile, with asynchronous Rust, everything seems <a href="https://rust-lang.github.io/async-book/part-guide/async-await.html" rel="noreferrer">somehow god damn complicated</a>.</p><p>However, my point is that it only <strong><em>seems</em> </strong>complicated in Rust.</p><p>There are 2 reasons:</p><ol><li>The overall Rust complexity. It may complicate thinking and a learning curve. </li><li>The way how the asynchronous Rust is studied.</li></ol><p>I mean, a typical Rust guide, such as the <a href="https://rust-lang.github.io/async-book/" rel="noreferrer">async book</a>, quickly dives you into an in-depth exploration of async types and event loop implementation. It&apos;s the case when you can&apos;t see the forest behind the trees. In contrast, a typical Go guide skips the intricate details.</p><p>So, I think it can be really helpful - seeing something complex through the lens of simplicity.</p><p>Let&#x2019;s get straight to the point. I suggest the following <em>mind map</em>:</p><table>
<thead>
<tr>
<th>Go</th>
<th>Rust</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>go f(x)</code></td>
<td><code>spawn(f(x))</code></td>
</tr>
<tr>
<td><code>ch := make(chan int)</code></td>
<td><code>let (tx, rx) = mpsc::channel::&lt;i32&gt;(0)</code></td>
</tr>
<tr>
<td><code>ch &lt;- v</code></td>
<td><code>tx.send(v).await</code></td>
</tr>
<tr>
<td><code>v := &lt;-ch</code></td>
<td><code>let v = rx.recv().await</code></td>
</tr>
<tr>
<td><code>select</code></td>
<td><code>tokio::select!</code></td>
</tr>
</tbody>
</table>
<p>The Rust&apos;s <code>spawn</code> method may appear from different runtime crates, e.g. <code>tokio::spawn</code>, or <code>async_std::task::spawn</code>, however, the core concept remains the same. The <em>mental model</em> of running the &quot;green threads&quot; in Go (<em>&quot;<strong>go the func!</strong>&quot;</em>) maps closely to Rust&#x2019;s async tasks spawning (<em>&quot;<strong>spawn the task!</strong>&quot;</em>).</p>
<!--kg-card-begin: html-->
<p style="text-align: center;">&#x295;&#x25D4;&#x3D6;&#x25D4;&#x294; <code>go the func</code> = <code>spawn the task</code> &#x1F980;</p>
<!--kg-card-end: html-->
<p> Also, there are many similar instruments in both languages like synchronization channels and the <code>select</code> notion.</p><hr><h2 id="gospawn"><code>go</code> -&gt; <code>spawn</code></h2><p>Let&#x2019;s look at the <a href="https://go.dev/tour/concurrency/1" rel="noreferrer">Go&apos;s concurrency example</a> and compare it to its Rust equivalent.</p><pre><code class="language-go">package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func say(s string) {
	for i := 0; i &lt; 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func main() {
	go say(&quot;world&quot;)
	say(&quot;hello&quot;)
}</code></pre><p>The program creates a lightweight green thread (goroutine) to execute <code>say(&quot;world&quot;)</code> concurrently while the main function continues with <code>say(&quot;hello&quot;)</code>.</p><p>What is the Rust equivalent?</p><pre><code class="language-rust">use tokio::time::{sleep, Duration};

async fn say(s: &amp;str) {
    for _ in 0..5 {
        sleep(Duration::from_millis(100)).await;
        println!(&quot;{s}&quot;);
    }
}

#[tokio::main]
async fn main() {
    tokio::spawn(say(&quot;world&quot;));
    say(&quot;hello&quot;).await;
}
</code></pre><p><code>say(&quot;world&quot;)</code> runs concurrently using <code>tokio::spawn</code> while the main function continues with <code>say(&quot;hello&quot;)</code>. This causes &quot;hello&quot; to print five times while &quot;world&quot; prints concurrently, resulting in interleaved outputs.</p><p>Let&apos;s compare them closely.</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2024/12/IMG_20241229_212645_797.jpg" class="kg-image" alt="Rust GOes Async" loading="lazy" width="2000" height="1125" srcset="https://fadeevab.com/content/images/size/w600/2024/12/IMG_20241229_212645_797.jpg 600w, https://fadeevab.com/content/images/size/w1000/2024/12/IMG_20241229_212645_797.jpg 1000w, https://fadeevab.com/content/images/size/w1600/2024/12/IMG_20241229_212645_797.jpg 1600w, https://fadeevab.com/content/images/2024/12/IMG_20241229_212645_797.jpg 2000w" sizes="(min-width: 720px) 720px"></figure><p><strong><em>Go</em></strong></p><pre><code class="language-go">go say(&quot;world&quot;)</code></pre><p><strong><em>Rust</em></strong></p><pre><code class="language-rust">tokio::spawn(say(&quot;world&quot;))</code></pre><p>A similar <code>async-std</code> approach would look like this:</p><pre><code class="language-rust">async_std::task::spawn(say(&quot;world&quot;));
</code></pre><p>&#x1F4A1; <code>spawn(f(x))</code> starts a new asynchronous task managed by an asynchronous runtime.</p><p>&#x1F6A9; <em>The example is simplified: the spawned task should be awaited in the <code>main()</code> function; otherwise, the program will exit as soon as <code>say(&quot;hello&quot;)</code> in <code>main()</code> finishes its job. The example works because <code>main()</code> gives the spawned task enough time by printing 5 lines.</em></p><p>Rust syntax is more explicit.</p><p>Also, with Rust, a lot of &quot;meta-thinking&quot; is involved: what runtime to choose, and are there any compatibility issues? That&apos;s why <em>mental simplification</em> helps to get through all these complications.</p><p>The Rust syntax looks a little bit more scary. But it only <em>seems</em> scary.</p><ul><li><code>#[tokio::main]</code> annotation marks <code>async main</code> to be executed by the <code>tokio</code> runtime.<ul><li>In Go, there is only one option: a built-in runtime (even loop), while in Rust, developers have to choose among many options.</li></ul></li><li><code>async</code> in front of <code>main</code> is needed to mark an async context of execution:<ul><li>In Go this detail is hidden and managed by the language itself, but in Rust, there is a clear distinction between a synchronous execution and execution in an asynchronous context.</li></ul></li><li><code>tokio::spawn</code> specifies that the spawner belongs to the <code>tokio</code> crate.<ul><li>I prefer the explicitness of the <code>spawn</code> invocation via the &quot;<code>crate::spawn</code>&quot; notation because multiple crates may provide their own <code>spawn</code> function. For example, <code>ntex::spawn</code> can coexist with <code>tokio::spawn</code> - they are cross-compatible but behave slightly differently.</li></ul></li></ul><hr><h2 id="selecttokioselect"><code>select</code> -&gt; <code>tokio::select!</code></h2><p>Let&apos;s look at another asynchronous technique: <code>select</code>.</p>
<!--kg-card-begin: html-->
<p style="text-align: center;">&#x295;&#x25D4;&#x3D6;&#x25D4;&#x294; <code>select</code> = <code>tokio::select!</code> &#x1F980;</p>
<!--kg-card-end: html-->
<p><code>select</code> allows to wait on multiple concurrent branches. The basic pattern in Go and Rust is the following:</p><pre><code class="language-go">loop { // infinitely
    select { // only one of
        case #1: sending a message
        case #2: waiting for a message
        case #3: doing something async
     }
}</code></pre><p>Let&apos;s take a concurrent Go&apos;s <a href="https://go.dev/tour/concurrency/5" rel="noreferrer">Fibonacci example</a>.</p><pre><code class="language-go">func fibonacci(c, quit chan int) {
	x, y := 0, 1
	for {
		select {
		case c &lt;- x:
			x, y = y, x+y
		case &lt;-quit:
			fmt.Println(&quot;quit&quot;)
			return
		}
	}
}</code></pre><p>A Rust equivalent looks as follows (pay attention to the comment lines!):</p><pre><code class="language-rust">async fn fibonacci(c: mpsc::Sender&lt;i32&gt;, mut quit: mpsc::Receiver&lt;()&gt;) {
    let (mut x, mut y) = (0, 1);

    loop { // for
        tokio::select! { // select
            _ = c.send(x) =&gt; { // case c &lt;- x
                (x, y) = (y, x + y);
            }
            Some(_) = quit.recv() =&gt; { // case &lt;-quit
                println!(&quot;quit&quot;);
                return;
            }
        }
    }</code></pre><p>Rust code is more verbose and explicit, but functionally identical. Here&apos;s the visual recap:</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2024/12/IMG_20241229_230737_677.jpg" class="kg-image" alt="Rust GOes Async" loading="lazy" width="2000" height="1125" srcset="https://fadeevab.com/content/images/size/w600/2024/12/IMG_20241229_230737_677.jpg 600w, https://fadeevab.com/content/images/size/w1000/2024/12/IMG_20241229_230737_677.jpg 1000w, https://fadeevab.com/content/images/size/w1600/2024/12/IMG_20241229_230737_677.jpg 1600w, https://fadeevab.com/content/images/2024/12/IMG_20241229_230737_677.jpg 2000w" sizes="(min-width: 720px) 720px"></figure><hr><h2 id="simplify-the-mental-model">Simplify the Mental Model</h2><p>A straightforward <em>mental model </em>can ease the learning curve, making a Rust developer competitive in the backend development domain. For instance:</p><ol><li><code>go f(x)</code> = <code>spawn(f(x))</code></li><li><code>async fn</code> is just a &quot;Future&quot;, and &quot;Future&quot; is just a state machine</li><li>Rust channels are as easy as in Go</li><li>async block <code>async {}</code> is my friend :)</li><li>etc.</li></ol><p>Async programming in Rust doesn&#x2019;t have to be any more intimidating. With the right framing, it can be just as accessible and intuitive.</p>]]></content:encoded></item><item><title><![CDATA[2024 Year In Code]]></title><description><![CDATA[<p>Here&#x2019;s a quick recap of my <strong>2024 in code </strong> &#x1F680;, thanks to <a href="https://git-wrapped.com" rel="noopener">git-wrapped.com</a>!</p><p>GitHub: <a href="https://github.com/fadeevab/">https://github.com/fadeevab/</a><br>&#x1F31F; Universal Rank: Top 5%<br>&#x1F525; Top Language: Rust<br>&#x2B50; Stars Earned: 1,383<br>&#x1F3C6; Total Commits: 566<br>&#x1F389; Most Active Month: November</p><p>&#x1F609; GitHub doesn&apos;t track</p>]]></description><link>https://fadeevab.com/2024-year-in-code/</link><guid isPermaLink="false">676c66f0999a550535a4226c</guid><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Wed, 25 Dec 2024 20:42:08 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2024/12/git-wrapped-fadeevab.png" medium="image"/><content:encoded><![CDATA[<img src="https://fadeevab.com/content/images/2024/12/git-wrapped-fadeevab.png" alt="2024 Year In Code"><p>Here&#x2019;s a quick recap of my <strong>2024 in code </strong> &#x1F680;, thanks to <a href="https://git-wrapped.com" rel="noopener">git-wrapped.com</a>!</p><p>GitHub: <a href="https://github.com/fadeevab/">https://github.com/fadeevab/</a><br>&#x1F31F; Universal Rank: Top 5%<br>&#x1F525; Top Language: Rust<br>&#x2B50; Stars Earned: 1,383<br>&#x1F3C6; Total Commits: 566<br>&#x1F389; Most Active Month: November</p><p>&#x1F609; GitHub doesn&apos;t track analytical and design activity unless you submit it.</p><p>Now, I&apos;m dealing with EMV blockchains, Web3, and multi-language environments. More of a backend, DevOps, meshes, RPCs, etc. A bit more of async Rust &#x1F980;. Let&apos;s see what the next year brings us.</p><p>Either way, my <a href="https://crates.io/crates/cliclack" rel="noreferrer">cliclack</a> (~1k&#x2B50;) shows traction. I can&apos;t believe it&apos;s been over a year since I published it as a side activity:</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2024/12/image.png" class="kg-image" alt="2024 Year In Code" loading="lazy" width="930" height="805" srcset="https://fadeevab.com/content/images/size/w600/2024/12/image.png 600w, https://fadeevab.com/content/images/2024/12/image.png 930w" sizes="(min-width: 720px) 720px"></figure><p>My good-old <a href="https://crates.io/crates/cocoon" rel="noreferrer">cocoon</a> feels good as well:</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2024/12/image-1.png" class="kg-image" alt="2024 Year In Code" loading="lazy" width="936" height="821" srcset="https://fadeevab.com/content/images/size/w600/2024/12/image-1.png 600w, https://fadeevab.com/content/images/2024/12/image-1.png 936w" sizes="(min-width: 720px) 720px"></figure><p>Grateful for all the challenges and growth this year. Here&apos;s to even more in 2025!</p>]]></content:encoded></item><item><title><![CDATA[Comparison of Rust 🦀 CLI Prompts: cliclack, dialoguer,  promptly, and inquire]]></title><description><![CDATA[Let's compare 4 different command line prompt crates by running their basic examples: cliclack, dialoguer, promptly, inquire.]]></description><link>https://fadeevab.com/comparison-of-rust-cli-prompts/</link><guid isPermaLink="false">64b7fc668af9a032e8de017f</guid><category><![CDATA[Development]]></category><category><![CDATA[Rust]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Wed, 19 Jul 2023 16:43:43 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2023/07/rust-cli-prompts-4.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://fadeevab.com/content/images/2023/07/rust-cli-prompts-4.jpg" alt="Comparison of Rust &#x1F980; CLI Prompts: cliclack, dialoguer,  promptly, and inquire"><p>Let&apos;s compare 4 different command line prompt crates by running their basic examples.</p><h2 id="cliclack">cliclack</h2><p>Crate: <a href="https://crates.io/crates/cliclack">https://crates.io/crates/cliclack</a><br>GitHub: <a href="https://github.com/fadeevab/cliclack">https://github.com/fadeevab/cliclack</a></p><p><code><strong>cliclack</strong></code><strong> is a &quot;Clack for Rust&quot;</strong> (clone of npm <a href="https://www.npmjs.com/package/@clack/prompts">@clack/prompts</a>).</p><p>How to run:</p><pre><code class="language-bash">cargo run --example basic</code></pre><p>Result:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2023/07/cliclack-demo.gif" class="kg-image" alt="Comparison of Rust &#x1F980; CLI Prompts: cliclack, dialoguer,  promptly, and inquire" loading="lazy" width="720" height="720" srcset="https://fadeevab.com/content/images/size/w600/2023/07/cliclack-demo.gif 600w, https://fadeevab.com/content/images/2023/07/cliclack-demo.gif 720w" sizes="(min-width: 720px) 720px"><figcaption>The example is taken from <a href="https://github.com/fadeevab/cliclack">https://github.com/fadeevab/cliclack</a></figcaption></figure><p>Theme support:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2023/07/image-4.png" class="kg-image" alt="Comparison of Rust &#x1F980; CLI Prompts: cliclack, dialoguer,  promptly, and inquire" loading="lazy" width="502" height="241"><figcaption>Full example: <a href="https://github.com/fadeevab/cliclack/blob/main/examples/theme.rs">https://github.com/fadeevab/cliclack/blob/main/examples/theme.rs</a></figcaption></figure><p>Sample code:</p><pre><code class="language-rust">intro(&quot;create-my-app&quot;)?;

let path: String = input(&quot;Where should we create your project?&quot;)
    .placeholder(&quot;./sparkling-solid&quot;)
    .validate(|input: &amp;String| {
        if input.is_empty() {
            Err(&quot;Please enter a path.&quot;)
        } else if !input.starts_with(&quot;./&quot;) {
            Err(&quot;Please enter a relative path&quot;)
        } else {
            Ok(())
        }
    })
    .interact()?;
    
let number: u8 = input(&quot;Input a number (not greater than 256)&quot;).interact()?;

outro(&quot;You&apos;re all set!&quot;)?;</code></pre><h2 id="dialoguer">dialoguer</h2><p>Crate: <a href="https://crates.io/crates/dialoguer">https://crates.io/crates/dialoguer</a><br>GitHub: <a href="https://github.com/mitsuhiko/dialoguer">https://github.com/mitsuhiko/dialoguer</a></p><p>How to run:</p><pre><code class="language-bash">cargo run --example input</code></pre><p>Result:</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2023/07/image.png" class="kg-image" alt="Comparison of Rust &#x1F980; CLI Prompts: cliclack, dialoguer,  promptly, and inquire" loading="lazy" width="952" height="388" srcset="https://fadeevab.com/content/images/size/w600/2023/07/image.png 600w, https://fadeevab.com/content/images/2023/07/image.png 952w" sizes="(min-width: 720px) 720px"></figure><p>Sample code:</p><pre><code class="language-rust">let mail: String = Input::with_theme(&amp;ColorfulTheme::default())
    .with_prompt(&quot;Your email&quot;)
    .validate_with({
        let mut force = None;
        move |input: &amp;String| -&gt; Result&lt;(), &amp;str&gt; {
            if input.contains(&apos;@&apos;) || force.as_ref().map_or(false, |old| old == input) {
                Ok(())
            } else {
                force = Some(input.clone());
                Err(&quot;This is not a mail address; type the same value again to force use&quot;)
            }
        }
    })
    .interact_text()
    .unwrap();</code></pre><h2 id="promptly">promptly</h2><p>Crate: <a href="https://crates.io/crates/promptly">https://crates.io/crates/promptly</a><br>GitHub: <a href="https://github.com/anowell/promptly">https://github.com/anowell/promptly</a></p><p>How to run:</p><pre><code class="language-bash">cargo run --example basic</code></pre><p>Result:</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2023/07/image-1.png" class="kg-image" alt="Comparison of Rust &#x1F980; CLI Prompts: cliclack, dialoguer,  promptly, and inquire" loading="lazy" width="970" height="817" srcset="https://fadeevab.com/content/images/size/w600/2023/07/image-1.png 600w, https://fadeevab.com/content/images/2023/07/image-1.png 970w" sizes="(min-width: 720px) 720px"></figure><p>Sample code:</p><pre><code class="language-rust">use promptly::{prompt, prompt_default, prompt_opt};

// Prompt until a non-empty string is provided
let name: String = prompt(&quot;Enter your name&quot;)?;

// Prompt for other `FromStr` types
let age: u32 = prompt(&quot;Enter your age&quot;)?;

// Prompt for optional paths with path completion. Returns `None` if empty input.
let photo: Option&lt;PathBuf&gt; = prompt_opt(&quot;Enter a path to a profile picture&quot;)?;

// Prompt Y/n with a default value when input is empty
let fallback = prompt_default(&quot;Would you like to receive marketing emails&quot;, true);

// Prompt for a url using the url crate (requires either &apos;nightly&apos; or &apos;url&apos; feature)
let website: Url = prompt(&quot;Enter a website URL&quot;);</code></pre><h2 id="inquire">inquire</h2><p>Crate: <a href="https://crates.io/crates/inquire">https://crates.io/crates/inquire</a><br>GitHub: <a href="https://github.com/mikaelmello/inquire">https://github.com/mikaelmello/inquire</a></p><p>How to run:</p><pre><code class="language-bash"> cargo run --example expense_tracker --features=&quot;date macros&quot;</code></pre><p>Result:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2023/07/expense_tracker.gif" class="kg-image" alt="Comparison of Rust &#x1F980; CLI Prompts: cliclack, dialoguer,  promptly, and inquire" loading="lazy" width="1468" height="600" srcset="https://fadeevab.com/content/images/size/w600/2023/07/expense_tracker.gif 600w, https://fadeevab.com/content/images/size/w1000/2023/07/expense_tracker.gif 1000w, https://fadeevab.com/content/images/2023/07/expense_tracker.gif 1468w" sizes="(min-width: 720px) 720px"><figcaption>The example is taken from https://github.com/mikaelmello/inquire</figcaption></figure><p>Sample code:</p><pre><code class="language-rust">let _payee = Text::new(&quot;Payee:&quot;)
    .with_validator(required!(&quot;This field is required&quot;))
    .with_autocomplete(&amp;payee_suggestor)
    .with_help_message(&quot;e.g. Music Store&quot;)
    .with_page_size(5)
    .prompt()?;

let amount: f64 = CustomType::new(&quot;Amount:&quot;)
    .with_formatter(&amp;|i: f64| format!(&quot;${i}&quot;))
    .with_error_message(&quot;Please type a valid number&quot;)
    .with_help_message(&quot;Type the amount in US dollars using a decimal point as a separator&quot;)
    .prompt()
    .unwrap();</code></pre>]]></content:encoded></item><item><title><![CDATA[My Configs for a Fancy-Looking Terminal (starship, exa, fonts)]]></title><description><![CDATA[My starship and exa configs for a fancy command prompt in bash and pwsh (PowerShell). How to beautify the terminal with nerd fonts and a nice background. Making it work in Windows Terminal. Within an SSH session, under both root and non-root users.]]></description><link>https://fadeevab.com/my-configs-for-fancy-looking-terminal-starship-exa/</link><guid isPermaLink="false">642c1b6708d891491f029e3b</guid><category><![CDATA[Development]]></category><category><![CDATA[Misc]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Tue, 04 Apr 2023 19:49:17 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2023/04/fadeevab_starship_config_collage-1.png" medium="image"/><content:encoded><![CDATA[<figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="https://fadeevab.com/safeskies/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Safe Skies</div><div class="kg-bookmark-description">Join Timothy Snyder&#x2019;s fundraiser! &#x1F447; Safe SkiesJoin Timothy Snyder&#x2019;s fundraiser! The history professor is raising funds towards a situational alert system for Ukraine&#x2019;s Air Defence Forces. Protect Ukrainian towns from terrorist attacks.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://fadeevab.com/content/images/size/w256h256/2018/07/fadeevabico.png" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)"><span class="kg-bookmark-author">Alexander Fadeev&apos;s Blog</span><span class="kg-bookmark-publisher">Alexandr Fadeev</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://fadeevab.com/content/images/2018/07/fadeevabcov.jpg" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)"></div></a><figcaption><img src="https://fadeevab.com/content/images/2023/04/fadeevab_starship_config_collage-1.png" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)"><p><span style="white-space: pre-wrap;">Safe Skies is an innovative </span><b><strong style="white-space: pre-wrap;">sensor system for detecting air targets</strong></b></p></figcaption></figure><p>My terminal environment is usually customized as follows:</p><ol><li><a href="https://starship.rs/">starship</a> for a nice command-line prompt,</li><li><a href="https://the.exa.website/">exa</a> for a nice directory listing instead of original <code>ls</code>,</li><li><a href="https://www.nerdfonts.com/font-downloads">nerdfonts</a> for beautiful glyphs in the terminal application,</li><li><a href="https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701">Windows Terminal</a>, as a terminal application for setting up all the beauty.</li></ol><p><code>bash</code> is the main shell I usually work in.</p><p><em>&#x1F449; All instructions below work in a <strong>Linux </strong>environment including SSH sessions.</em></p><p>Terminal emulator allows rendering custom fonts and backgrounds (like those little cartoonish bulbs &#x1F4A1;). I use <em>Windows Terminal</em> as a terminal application (terminal emulator) in Windows for simultaneous access to <em>different terminal environments</em> and shells <em>in different tabs</em>, I mainly use two environments:</p><ol><li><strong><em>Ubuntu </em></strong>in Windows Subsystem for Linux (WSL2) with <code>bash</code> shell.</li><li><strong><em>Windows </em></strong>environment enabled with <code>pwsh</code> (PowerShell).</li></ol><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2023/06/fadeevab_starhip_config_explanation.png" class="kg-image" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy" width="1136" height="637" srcset="https://fadeevab.com/content/images/size/w600/2023/06/fadeevab_starhip_config_explanation.png 600w, https://fadeevab.com/content/images/size/w1000/2023/06/fadeevab_starhip_config_explanation.png 1000w, https://fadeevab.com/content/images/2023/06/fadeevab_starhip_config_explanation.png 1136w" sizes="(min-width: 720px) 720px"></figure><p>There are plenty of terminal emulators in different Linux distros, e.g. GNOME Terminal on Ubuntu, they can be configured to render different fonts and backgrounds.</p><p>&#x1F4A1;<em> Just remember:</em></p><ol><li><em>backgrounds and the fancy fonts &#x1F3A8; are in the <strong>terminal </strong>settings (GNOME, Windows Terminal)</em></li><li><em>while the command prompt </em> <em>(&#x1F680; starship) is in the <strong>shell </strong>configuration </em>(bash, fish, pwsh)<em>.</em></li></ol><hr><h2 id="%F0%9F%9A%80-starship">&#x1F680; Starship</h2><p><a href="https://starship.rs/guide/#%F0%9F%9A%80-installation">Starship</a> is used for a nice-looking command prompt.</p><h3 id="how-to-install">How to Install</h3><p>The following steps work in any Linux, you can even quickly beautify your SSH session on the remote host!</p><pre><code class="language-bash">sudo apt install gcc cmake

curl --proto &apos;=https&apos; --tlsv1.2 -sSf https://sh.rustup.rs | sh
source &quot;$HOME/.cargo/env&quot;

cargo install starship
eval &quot;$(starship init bash)&quot;</code></pre><p>Add the next line into <code>~/.bashrc</code>:</p><pre><code class="language-bash"> eval &quot;$(starship init bash)&quot;</code></pre><p>Don&apos;t forget to apply.</p><pre><code class="language-bash">source ~/.bashrc</code></pre><p>How the command prompt finally looks:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2023/04/image-5.png" class="kg-image" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy" width="850" height="82" srcset="https://fadeevab.com/content/images/size/w600/2023/04/image-5.png 600w, https://fadeevab.com/content/images/2023/04/image-5.png 850w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Starship shows information about </span><code spellcheck="false" style="white-space: pre-wrap;"><span>git</span></code><span style="white-space: pre-wrap;"> repository instead of a long local path (you have to </span><code spellcheck="false" style="white-space: pre-wrap;"><span>cd</span></code><span style="white-space: pre-wrap;"> into the Git repo directory): </span><code spellcheck="false" style="white-space: pre-wrap;"><span>cocoon</span></code><span style="white-space: pre-wrap;"> Git repo, </span><code spellcheck="false" style="white-space: pre-wrap;"><span>main</span></code><span style="white-space: pre-wrap;"> branch, </span><code spellcheck="false" style="white-space: pre-wrap;"><span>rust</span></code><span style="white-space: pre-wrap;"> v1.67.0, Ubuntu </span><code spellcheck="false" style="white-space: pre-wrap;"><span>&#xEBC9;</span></code><span style="white-space: pre-wrap;">, bash </span><code spellcheck="false" style="white-space: pre-wrap;"><span>&#xEBCA;</span></code></figcaption></figure><h3 id="root-user">Root User</h3><p>&#x1F46E;&#x200D;&#x2642;&#xFE0F; Additionally, set up <code>starship</code> for the <strong>root</strong> user.</p><p>Change a shell user to be a <code>root</code> user.</p><pre><code class="language-bash">sudo su

vi ~/.bashrc
</code></pre><p>Add the following line into <code>/root/.bashrc</code> (it&apos;s literally <em>~/.bashrc</em> for the root user... and don&apos;t forget to change the &quot;<code>&lt;user&gt;</code>&quot; part of the command line below - this is the <em>non-root user you came from</em>).</p><pre><code class="language-bash">eval &quot;$(/home/&lt;user&gt;/.cargo/bin/starship init bash)&quot;</code></pre><p>Run the command above in the command line or apply the config:</p><pre><code class="language-bash">source .bashrc</code></pre><p>How it finally looks for the root:</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2023/04/image-12-1.png" class="kg-image" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy" width="986" height="183" srcset="https://fadeevab.com/content/images/size/w600/2023/04/image-12-1.png 600w, https://fadeevab.com/content/images/2023/04/image-12-1.png 986w" sizes="(min-width: 720px) 720px"></figure><h3 id="ssh">SSH</h3><p>&#x1F30E; You can install <code>starship</code> on the remote node within an SSH session.</p><p>Just open an SSH session (like <code>ssh alex@dsn-play-alex-01</code> in my case), and then follow the instructions above (rustup install , <code>cargo install starship</code>, etc.) and you will able to see something as follows after <code>ssh</code> login (command prompt shows you have a remote connection to some host):</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2023/04/image-10.png" class="kg-image" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy" width="496" height="76"><figcaption><span style="white-space: pre-wrap;">Setting up </span><code spellcheck="false" style="white-space: pre-wrap;"><span>starship</span></code><span style="white-space: pre-wrap;"> on different hosts helps to distinguish a remote and a local hosts</span></figcaption></figure><h3 id="%F0%9F%94%A7-starship-bash-config">&#x1F527; Starship <code>bash</code> config</h3><p>It&apos;s about how exactly Starship is going to render the command prompt.</p><pre><code class="language-bash">cat ~/.config/starship.toml</code></pre><pre><code class="language-toml">[shlvl]
disabled = false
threshold = 2
symbol = &quot;\uf07d&quot;

[shell]
disabled = false
bash_indicator = &quot;&#xEBCA;&quot;

[os]
disabled = false
format = &quot;$symbol &quot;
symbols.Ubuntu = &quot;&#xEBC9;&quot;</code></pre><ul><li><code>shlvl</code> config makes it show the number of a shell level, e.g. it shows &quot;&#x2195;&#xFE0F; 1&quot; when running under <code>mc</code> (Midnight Commander).</li><li><code>shell</code> module helps identify a shell that is currently in use (<code>bash</code>, <code>fish</code>, <code>pwsh</code>). </li><li><code>os</code> module shows the operating system.</li></ul><p>The last 2 options are needed because I can open a tab with PowerShell, and, with properly configured Starship, it allows me to recognize shells between each other quickly.</p><h3 id="powershell-installation-notes">PowerShell Installation Notes</h3><p>You can find instructions here: <a href="https://starship.rs/guide/#%F0%9F%9A%80-installation">https://starship.rs/guide/#&#x1F680;-installation</a></p><p>The biggest challenge is to find where is the PowerShell config. Mine was here: <code>C:\Users\user\OneDrive\Documents\PowerShell\Microsoft.PowerShell_profile.ps1</code>.</p><p>Here is its content:</p><pre><code class="language-powershell"># Starship
Invoke-Expression (&amp;starship init powershell)
</code></pre><p>Meanwhile, the Starship config is here: <code>$HOME/.config/starship.toml</code>.</p><h3 id="%F0%9F%94%A7-starship-powershell-pwsh-config">&#x1F527; Starship PowerShell <code>pwsh</code> config</h3><pre><code class="language-bash">cat ~\.config\starship.toml</code></pre><pre><code class="language-toml">[shell]
disabled = false
powershell_indicator = &quot;&#xEBC7;&quot;
cmd_indicator = &quot;&#xEBC4;&quot;

[os]
disabled = false
format = &quot;$symbol &quot;
symbols.Windows = &quot;&#xE70F;&quot;</code></pre><h3 id="how-it-looks-in-tabs">How It Looks in Tabs</h3><p>In the following example, I can quickly distinguish OS and shells via nice glyphs: <code>&#xEBC9;</code> <code>&#xEBCA;</code> <code>&#xE70F;</code> <code>&#xEBC7;</code>.</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2023/04/image-19.png" class="kg-image" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy" width="1297" height="235" srcset="https://fadeevab.com/content/images/size/w600/2023/04/image-19.png 600w, https://fadeevab.com/content/images/size/w1000/2023/04/image-19.png 1000w, https://fadeevab.com/content/images/2023/04/image-19.png 1297w" sizes="(min-width: 720px) 720px"></figure><p><code>&#xEBC9;</code> <code>&#xEBCA;</code> <em>Tab #1 </em>can be a WSL2 Ubuntu/Linux <code>bash</code> terminal:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2023/04/image-18.png" class="kg-image" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy" width="519" height="241"><figcaption><span style="white-space: pre-wrap;">Ubuntu </span><code spellcheck="false" style="white-space: pre-wrap;"><span>&#xEBC9;</span></code><span style="white-space: pre-wrap;">, bash </span><code spellcheck="false" style="white-space: pre-wrap;"><span>&#xEBCA;</span></code><span style="white-space: pre-wrap;">, shell level 1 under </span><code spellcheck="false" style="white-space: pre-wrap;"><span>mc</span></code><span style="white-space: pre-wrap;">, path </span><code spellcheck="false" style="white-space: pre-wrap;"><span>~/.config</span></code></figcaption></figure><p><code>&#xE70F;</code> <code>&#xEBC7;</code> <em>Tab #2</em> can be a PowerShell <code>pwsh</code> terminal:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2023/04/image-7.png" class="kg-image" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy" width="393" height="88"><figcaption><span style="white-space: pre-wrap;">Windows </span><code spellcheck="false" style="white-space: pre-wrap;"><span>&#xE70F;</span></code><span style="white-space: pre-wrap;">, PowerShell </span><code spellcheck="false" style="white-space: pre-wrap;"><span>&#xEBC7;</span></code><span style="white-space: pre-wrap;">, path </span><code spellcheck="false" style="white-space: pre-wrap;"><span>~\.config</span></code></figcaption></figure><hr><h2 id="%F0%9F%A6%80-exa">&#x1F980; =exa=</h2><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2023/04/fadeevab_exa.png" class="kg-image" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy" width="1164" height="261" srcset="https://fadeevab.com/content/images/size/w600/2023/04/fadeevab_exa.png 600w, https://fadeevab.com/content/images/size/w1000/2023/04/fadeevab_exa.png 1000w, https://fadeevab.com/content/images/2023/04/fadeevab_exa.png 1164w" sizes="(min-width: 720px) 720px"></figure><p><code>exa</code> is a modern replacement for <code>ls</code> written in Rust.</p><p>How to install:</p><pre><code class="language-bash">sudo apt install exa</code></pre><p>Modify <code>~/.bashrc</code> config. If the <code>ls</code> alias is already defined there, then substitute it with the following line:</p><pre><code class="language-bash">alias ls=&apos;exa --icons -F -H --group-directories-first --git -1&apos;</code></pre><ul><li><code>--icons</code> shows the icons (I want a fancy look!)</li><li><code>-F</code> type indicators</li><li><code>-H</code> hard links</li><li><code>--group-directories-first</code> list directories before other files</li><li><code>--git</code> list each file&apos;s Git status</li><li><code>-1</code> show a table listing, 1 entry by line</li></ul><p>And <code>ll</code> is usually already defined like this:</p><pre><code class="language-bash">alias ll=&apos;ls -alF&apos;</code></pre><hr><h2 id="%F0%9F%93%BA-windows-terminal">&#x1F4FA; Windows Terminal</h2><p>Finally, a proper setup of the Windows Terminal is needed to fully enable <code>starship</code> and <code>exa</code> showing fancy fonts (e.g. &quot;nerd&quot; glyphs <code>&#xEBC9;</code>, <code>&#xEBCA;</code>) on a custom background (&#x1F4A1;) with support of different terminal environments (e.g. <code>bash</code>, <code>pwsh</code>).</p><ol>
<li>
<p>Install the <strong>Windows Terminal</strong> from the Microsoft Store: <a href="https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701">https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701</a></p>
</li>
<li>
<p>Install <strong>Nerd Fonts</strong>. Download a <em>&quot;FiraCode Nerd Font&quot;</em>: <a href="https://github.com/ryanoasis/nerd-fonts/releases/download/v2.3.3/FiraCode.zip">https://github.com/ryanoasis/nerd-fonts/releases/download/v2.3.3/FiraCode.zip</a></p>
<p>Find the <code>Fira Code Retina Nerd Font Complete Mono Windows Compatible.ttf</code> inside of the archive and install it (double click).</p>
<p>&#x1F4A1; You can find more nerd fonts at <a href="https://www.nerdfonts.com">nerdfonts.com</a>.</p>
<p><img src="https://fadeevab.com/content/images/2023/04/firacode_nerd_font_donwload.png" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy"></p>
</li>
<li>
<p>Set the <strong>Campbell</strong> color theme and <strong>FiraCode NFR Retina</strong> font, installed in the previous step:<br>
<img src="https://fadeevab.com/content/images/2023/04/windows_terminal_config.png" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy"></p>
</li>
<li>
<p>Download my bulbs <strong>background</strong> (Right Click -&gt; Save Image As...):<br>
<img src="https://fadeevab.com/content/images/2023/04/light-bulb-minimalism-wallpaper-c26162b00db69e6bba0822c520f849d2.jpg" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy"><br>
And set it in the Windows Terminal:<br>
<img src="https://fadeevab.com/content/images/2023/04/windows_terminal_config_background.png" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy"></p>
</li>
</ol>
<hr><p>Voila!</p><p>My final setup is shown in the initial screenshot at the beginning of the article:</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2023/04/fadeevab_starhip_config_screenshot_light-1.png" class="kg-image" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy" width="1136" height="637" srcset="https://fadeevab.com/content/images/size/w600/2023/04/fadeevab_starhip_config_screenshot_light-1.png 600w, https://fadeevab.com/content/images/size/w1000/2023/04/fadeevab_starhip_config_screenshot_light-1.png 1000w, https://fadeevab.com/content/images/2023/04/fadeevab_starhip_config_screenshot_light-1.png 1136w" sizes="(min-width: 720px) 720px"></figure><hr><h2 id="visual-studio-code"> Visual Studio Code</h2><p>For the VSCode the mentioned nerd fonts look pretty bold, so I use another nerd font: <strong>Hasklug</strong>.</p><ol><li>Download it from the <a href="https://www.nerdfonts.com/font-downloads">nerdfonts.com</a>.</li><li>Find a <code>HasklugNerdFontMono-Light.otf</code> inside.</li></ol><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2026/03/-----------1.png" class="kg-image" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy" width="1212" height="680" srcset="https://fadeevab.com/content/images/size/w600/2026/03/-----------1.png 600w, https://fadeevab.com/content/images/size/w1000/2026/03/-----------1.png 1000w, https://fadeevab.com/content/images/2026/03/-----------1.png 1212w" sizes="(min-width: 720px) 720px"></figure><p>Go to <code>code</code>&apos;s Settings &gt; Editor: Font Family and add &apos;Hasklug Nerd Font Mono&apos;.</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2026/03/-----------3.png" class="kg-image" alt="My Configs for a Fancy-Looking Terminal (starship, exa, fonts)" loading="lazy" width="928" height="212" srcset="https://fadeevab.com/content/images/size/w600/2026/03/-----------3.png 600w, https://fadeevab.com/content/images/2026/03/-----------3.png 928w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA[Design Patterns in Rust: 100% Unique Idiomatic Examples]]></title><description><![CDATA[GitHub: https://github.com/fadeevab/design-patterns-rust 👈 My repository contains 100% fresh unique idiomatic Rust examples covering all 23 classic design patterns.]]></description><link>https://fadeevab.com/design-patterns-in-rust/</link><guid isPermaLink="false">6303b44252d1be591c5ed316</guid><category><![CDATA[Development]]></category><category><![CDATA[Rust]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Mon, 22 Aug 2022 17:11:26 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2022/08/fadeevab-design-patterns-rust.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://fadeevab.com/content/images/2022/08/fadeevab-design-patterns-rust.jpg" alt="Design Patterns in Rust: 100% Unique Idiomatic Examples"><p><em>GitHub repo: <a href="https://github.com/fadeevab/design-patterns-rust">https://github.com/fadeevab/design-patterns-rust</a></em></p><figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="https://github.com/fadeevab/design-patterns-rust"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - fadeevab/design-patterns-rust: Rust examples for all 23 classic GoF design patterns, and even a little more</div><div class="kg-bookmark-description">Rust examples for all 23 classic GoF design patterns, and even a little more - GitHub - fadeevab/design-patterns-rust: Rust examples for all 23 classic GoF design patterns, and even a little more</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="Design Patterns in Rust: 100% Unique Idiomatic Examples"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">fadeevab</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/ab6adc31813eb56fdaa31c679d16455bc631afefe956d72c03435e0d731a2b25/fadeevab/design-patterns-rust" alt="Design Patterns in Rust: 100% Unique Idiomatic Examples"></div></a><figcaption>Design Patterns in Rust</figcaption></figure><p>My repository contains unique <strong>Rust</strong> examples covering<strong> all 23 GoF classic design patterns</strong>. It already has ~100&#x2B50;.</p><p>The repository contains an exhausting list of design pattern examples in <strong>Rust</strong>. I rigorously worked on each pattern to showcase a good meaningful way to apply each of them specifically in Rust.</p><p>I wanted to challenge the Rust language specifically on whether it can adapt literally any OOP concept existing at the moment, and it passed the challenge.</p><p>Previously, I highlighted the <a href="https://fadeevab.com/mediator-pattern-in-rust/">Mediator</a> pattern in detail and some <a href="https://fadeevab.com/the-easiest-patterns-in-rust/">creational patterns</a>.</p><p>There are examples with visual output, like <a href="https://github.com/fadeevab/design-patterns-rust/tree/main/structural/flyweight">Flyweight</a>: drawing a forest of million trees &#x1F333;.</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2022/08/forest.png" class="kg-image" alt="Design Patterns in Rust: 100% Unique Idiomatic Examples" loading="lazy" width="904" height="904" srcset="https://fadeevab.com/content/images/size/w600/2022/08/forest.png 600w, https://fadeevab.com/content/images/2022/08/forest.png 904w" sizes="(min-width: 720px) 720px"></figure><p><a href="https://github.com/fadeevab/design-patterns-rust/tree/main/behavioral/state">State</a> is another worth mentioning pattern: let&apos;s build a <a href="https://github.com/fadeevab/design-patterns-rust/tree/main/behavioral/state">Music &#x1F4FC; Player</a>! </p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2022/08/playing.png" class="kg-image" alt="Design Patterns in Rust: 100% Unique Idiomatic Examples" loading="lazy" width="661" height="384" srcset="https://fadeevab.com/content/images/size/w600/2022/08/playing.png 600w, https://fadeevab.com/content/images/2022/08/playing.png 661w"></figure><p>Some patterns are really <a href="https://fadeevab.com/the-easiest-patterns-in-rust/">easy to implement</a> in Rust, mostly <em>creational</em> ones, e.g. <a href="https://github.com/fadeevab/design-patterns-rust/blob/main/creational/prototype">Prototype</a>, <a href="https://github.com/fadeevab/design-patterns-rust/blob/main/creational/static-creation-method">Static Creation Method</a>.</p><p>The <a href="https://github.com/fadeevab/design-patterns-rust/blob/main/behavioral/mediator">Mediator</a> <em>behavioral</em> pattern is the hardest to implement with Rust, considering Rust&apos;s specific ownership model with strict borrow checker rules.</p><p>Interestingly, in Rust:</p><ol><li>Almost all <strong>structural</strong> and <strong>creational</strong> patterns can be implemented using <em>generics</em>, hence, <em>static dispatch</em>.</li><li>Most <strong>behavioral</strong> patterns can NOT be implemented using static dispatch, <em>instead</em>, they can be implemented only via <em>dynamic dispatch</em>.</li></ol><p>A well-thought pattern <em>classification </em>fits the Rust language <em>design </em>perfectly as &quot;behavior&quot; is dynamic in nature and &quot;structure&quot; is static.</p><p>Enjoy!</p>]]></content:encoded></item><item><title><![CDATA[The Easiest Patterns in Rust]]></title><description><![CDATA[A few software design patterns are seamlessly integrated into Rust, so we're using them without realizing them. Which is great!

A hint: it is 2 creational patterns.]]></description><link>https://fadeevab.com/the-easiest-patterns-in-rust/</link><guid isPermaLink="false">62ea55dfd075eb0bde25e645</guid><category><![CDATA[Rust]]></category><category><![CDATA[Development]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Wed, 03 Aug 2022 12:06:45 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1613923377958-603839f4dbcf?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDMyfHxsZWdvfGVufDB8fHx8MTY1OTUyODM1MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1613923377958-603839f4dbcf?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDMyfHxsZWdvfGVufDB8fHx8MTY1OTUyODM1MA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="The Easiest Patterns in Rust"><p>&#x1F9E0; <em>Previously, I wrote about the most difficult-to-implement software design pattern in Rust: </em><a href="https://fadeevab.com/mediator-pattern-in-rust/"><em>Mediator pattern in Rust</em></a><em>.</em></p><p>&#x1F9D0; <em>See all pattern examples here: <a href="https://fadeevab.com/design-patterns-in-rust/">100% Unique Idiomatic Examples of All Design Patterns in Rust</a>.</em></p><p>Now, let&apos;s talk about what is, in my opinion, the easiest patterns in Rust (from 23 classic design patterns).</p><p>Guess what the pattern is this:</p><pre><code class="language-rust">impl Circle {
    pub fn new(radius: u32) -&gt; Circle {
        Self { radius }
    }
}</code></pre><p>You likely wrote this code a million times in Rust.</p><p>&#x1F300; It is... &#x1F941;&#x1F941;&#x1F941; A <strong><em>Static Creation Method</em></strong><em> </em>(a little relative of a Factory Method). </p><p>There is a notion of &quot;constructor&quot; in a typical OOP language which is a default class method to create an object. Not in Rust: constructors are thrown away because there is nothing that couldn&apos;t be achieved with a static creation method.</p><p>In a typical constructor idiom, there is no way to gracefully handle a construction error, there are also limitations about the complexity of the construction code. On the other hand, there could be any number of static methods with any kind of complex logic, e.g. loading from a database.</p><p>There are <em>a few ways to define</em> a static creation method.</p><ol><li>A <code>default()</code> method from <code>Default</code> trait for construction with no parameters. Use either default <code>#[derive(Default)]</code>, or a manual trait implementation.</li></ol><pre><code class="language-rust">#[derive(Default)]
struct Circle;

let circle = Circle::default();</code></pre><p>2. A handwritten <code>new()</code> method for a custom object creation with parameters:</p><pre><code class="language-rust">impl Rectangle {
    pub fn new(width: u32, length: u32) -&gt; Rectangle {
        Self { width, length }
    }
}

let rectangle = Rectangle::new(10, 20);</code></pre><p>3. A <code>from_</code> prefixed method for constructing from a custom object (you can use any name, however, it&apos;s kind of a naming convention).</p><pre><code class="language-rust">let circle = Circle::from_shape(shape, 10, 20);</code></pre><p>4. Implement a <code>From&lt;&gt;</code> trait for constructing from a known type.</p><pre><code class="language-rust">impl From&lt;PriceData&gt; for FormattedData {
    fn from(price: PriceData) -&gt; FormattedData {
        FormattedData {
            text: format!(&quot;{} {}&quot;, price.one, price.two),
        }
    }
}

let formatted_data = price_data.into();</code></pre><hr><p>Alright!</p><p>Now, guess what the pattern is represented by the following snippet:</p><pre><code class="language-rust">#[derive(Clone)]
struct Rectangle {
    width, height: u32,
}

let rectangle1 = Rectangle::new(10, 20);
let mut rectangle2 = rectangle1.clone();
rectangle2.set_width(50);</code></pre><p>&#x1F300; It is a <em><strong>Prototype,</strong></em> a creational pattern that allows you to copy existing objects without depending on their types.</p><p>Rust has standard <code>Clone</code> implementation (via <code>#[derive(Clone)]</code>) for many types which makes Prototype easy and seamless to use.</p><p>The point is that some patterns must not be programmed in a too overcomplicated manner having convenient instruments coming with language. And it&apos;s cool having a piece of knowledge about 2 creational design patterns &quot;out-of-the-box&quot; with knowing Rust.</p><hr><p>As an outro, let me put a quote about the topic from Linkedin (by <a href="https://www.linkedin.com/feed/update/urn:li:groupPost:4973032-6960571174007283712?commentUrn=urn%3Ali%3Acomment%3A%28groupPost%3A4973032-6960571174007283712%2C6960577908864106496%29">Micha&#x142; Isalski</a>):</p><!--kg-card-begin: markdown--><blockquote>
<p>&quot;Design patterns are methods of achieving features that are not built-in into the language itself. In the old days there was a &quot;Variable&quot; design pattern, used in ASM. Guess what - now all languages have that built-in. The same case is shown here - Rust makes some patterns into no-ops, while others (memory-unsafe ones) into hard-to-achieve.</p>
</blockquote>
<!--kg-card-end: markdown--><p>Additional thanks to <a href="https://www.linkedin.com/feed/update/urn:li:groupPost:4973032-6960571174007283712?commentUrn=urn%3Ali%3Acomment%3A%28groupPost%3A4973032-6960571174007283712%2C6960640994614599680%29">Oliver Marc S.</a> for expanding the topic of the static creation method.</p>]]></content:encoded></item><item><title><![CDATA[The Hardest Pattern in Rust: Mediator]]></title><description><![CDATA[A typical Mediator pattern implementation with other languages is a classic anti-pattern in Rust: many objects hold mutable cross-references on each other, trying to mutate each other, which is a deadly sin in Rust - the compiler won't pass your first naive implementation unless it's oversimplified.]]></description><link>https://fadeevab.com/mediator-pattern-in-rust/</link><guid isPermaLink="false">62ea284ed075eb0bde25e5f4</guid><category><![CDATA[Development]]></category><category><![CDATA[Rust]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Wed, 03 Aug 2022 08:19:21 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2022/08/mediator-rust-2.png" medium="image"/><content:encoded><![CDATA[<img src="https://fadeevab.com/content/images/2022/08/mediator-rust-2.png" alt="The Hardest Pattern in Rust: Mediator"><p><em>&#x1F449; A code and a full explanation are here: <a href="https://github.com/fadeevab/mediator-pattern-rust">https://github.com/fadeevab/mediator-pattern-rust</a> &#xA0;(a Train Station example).</em></p><p>By definition, <a href="https://refactoring.guru/design-patterns/mediator" rel="nofollow">Mediator</a> restricts direct communications between the objects and forces them to collaborate only via a mediator object. It also stands for a Controller in the MVC (Model-View-Controller) pattern.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Problem</th>
<th>Solution</th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="https://fadeevab.com/content/images/2022/08/problem.png" alt="The Hardest Pattern in Rust: Mediator" loading="lazy"></td>
<td><img src="https://fadeevab.com/content/images/2022/08/solution.png" alt="The Hardest Pattern in Rust: Mediator" loading="lazy"></td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><h2 id="problem">Problem</h2><p>A common implementation in object-oriented languages looks like the following pseudo-code:</p><pre><code class="language-Java">Controller controller = new Controller();

// Every component has a link to a mediator (controller).
component1.setController(controller);
component2.setController(controller);
component3.setController(controller);

// A mediator has a link to every object.
controller.add(component1);
controller.add(component2);
controller.add(component2);</code></pre><p>&#x1F4A5; Now, let&apos;s read this in <strong>Rust</strong> terms: <em>&quot;<strong>mutable</strong> structures have <strong>mutable</strong> references to a <strong>shared mutable</strong> object (mediator) which in turn has mutable references back to those mutable structures&quot;</em>.</p><p>Basically, you can start to imagine the unequal battle against the Rust compiler and its borrow checker. It seems like a solution introduces more problems:</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2022/08/mediator-mut-problem.png" class="kg-image" alt="The Hardest Pattern in Rust: Mediator" loading="lazy" width="454" height="426"></figure><ol><li>Imagine that the control flow starts at point 1 (Checkbox) where the 1st <strong>mutable</strong> borrow happens.</li><li>The mediator (Dialog) interacts with another object at point 2 (TextField).</li><li>The TextField notifies the Dialog back about finishing a job and that leads to a <strong>mutable</strong> action at point 3... &#x1F4A5; Bang!</li></ol><p>The second mutable borrow breaks the compilation with an error (the first borrow was on point 1).</p><p>In Rust, a widespread Mediator implementation is mostly an anti-pattern.</p><h2 id="existing-primers">Existing Primers</h2><p>You might see a reference Mediator examples in Rust like <a href="https://crates.io/crates/cursive" rel="nofollow">this</a>: the example is too much synthetic - there are no mutable operations, at least at the level of trait methods.</p><p>The <a href="https://github.com/rust-unofficial/patterns">rust-unofficial/patterns</a> repository doesn&apos;t include a referenced Mediator pattern implementation as of now, see <a href="https://github.com/rust-unofficial/patterns/issues/233">Issue #233</a>.</p><p><strong>Nevertheless, we don&apos;t surrender.</strong></p><h2 id="%F0%9F%8E%8C-cross-referencing-with-rcrefcell">&#x1F38C; Cross-Referencing with <code>Rc&lt;RefCell&lt;..&gt;&gt;</code></h2><p>There is an example of a <a href="https://refactoring.guru/design-patterns/mediator/go/example" rel="nofollow">Station Manager example in Go</a>. Trying to make it with Rust leads to mimicking a typical OOP through reference counting and borrow checking with mutability in runtime (which has quite unpredictable behavior in runtime with panics here and there).</p><p>&#x1F449; That&apos;s how it works: <a href="https://github.com/fadeevab/mediator-pattern-rust/tree/main/mediator-dynamic">mediator-dynamic</a></p><p>&#x1F3C1; I would recommend this approach for applications that need multi-threaded support. (Also, it&apos;s a good reference of how the Rust compiler could be tricked).</p><p>&#x1F4C4; Real-world example: <code><a href="https://docs.rs/indicatif/latest/indicatif/struct.MultiProgress.html">indicatif::MultiProgress</a></code> (mediates progress bars with support of being used in multiple threads).</p><p>Key points:</p><ol><li>All trait methods look like <strong>read-only (<code>&amp;self</code>)</strong>: immutable <code>self</code> and immutable parameters.</li><li><code>Rc</code>, <code>RefCell</code> are extensively used under the hood to take responsibility for the <strong>mutable borrowing</strong> from compiler to runtime. Invalid implementation will lead to <em>panic in runtime.</em></li></ol><h2 id="%E2%A4%B5-top-down-ownership">&#x2935; Top-Down Ownership</h2><p>The key point is thinking in terms of OWNERSHIP.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2022/08/rust-mediator.jpg" class="kg-image" alt="The Hardest Pattern in Rust: Mediator" loading="lazy" width="521" height="467"><figcaption>A top-down ownership approach to implementing Mediator in Rust</figcaption></figure><p>1. A mediator takes ownership of all components.</p><p>2. A component doesn&apos;t preserve a reference to a mediator. Instead, it gets the reference via a method call. </p><pre><code class="language-rust">// A train gets a mediator object by reference.
pub trait Train {
    fn name(&amp;self) -&gt; &amp;String;
    fn arrive(&amp;mut self, mediator: &amp;mut dyn Mediator);
    fn depart(&amp;mut self, mediator: &amp;mut dyn Mediator);
}

// Mediator has notification methods.
pub trait Mediator {
    fn notify_about_arrival(&amp;mut self, train_name: &amp;str) -&gt; bool;
    fn notify_about_departure(&amp;mut self, train_name: &amp;str);
}</code></pre><p>3. Control flow starts from <code>fn main()</code> where the mediator receives external events/commands.</p><p>4. <code>Mediator</code> trait for the interaction between components (<code>notify_about_arrival</code>, <code>notify_about_departure</code>) is not the same as its external API for receiving external events (<code>accept</code>, <code>depart</code> commands from the main loop).</p><pre><code class="language-rust">let train1 = PassengerTrain::new(&quot;Train 1&quot;);
let train2 = FreightTrain::new(&quot;Train 2&quot;);

// Station has `accept` and `depart` methods,
// but it also implements `Mediator`.
let mut station = TrainStation::default();

// Station is taking ownership of the trains.
station.accept(train1);     
station.accept(train2);

// `train1` and `train2` have been moved inside,
// but we can use train names to depart them.
station.depart(&quot;Train 1&quot;);
station.depart(&quot;Train 2&quot;);
station.depart(&quot;Train 3&quot;);</code></pre><p>&#x1F449; A Train Station example <strong>without</strong> <code>Rc</code>, <code>RefCell</code> tricks, but <strong>with</strong> <code>&amp;mut self</code> and compiler-time borrow checking: <a href="https://github.com/fadeevab/mediator-pattern-rust/mediator-static-recommended">https://github.com/fadeevab/mediator-pattern-rust/mediator-static-recommended</a>.</p><p>&#x1F449; A real-world example of the approach: <a href="https://crates.io/crates/cursive" rel="nofollow">Cursive (TUI)</a>.</p><p>At least yet, what is not covered is asynchronous approaches, and queue-based event handling with bubble-up capability.</p>]]></content:encoded></item><item><title><![CDATA[CI/CD + SAST: Expectation vs Reality]]></title><description><![CDATA[It's often hard to deliver security scan results synchronously, blocking the merge as a consequence of security verification. And you don't want to pass the vulnerable code to the release.]]></description><link>https://fadeevab.com/ci-cd-sast-challenges/</link><guid isPermaLink="false">61e09d050dda41594dc42bad</guid><category><![CDATA[Security]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Fri, 14 Jan 2022 13:53:26 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2022/01/SAST-perfect-pipeline-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://fadeevab.com/content/images/2022/01/SAST-perfect-pipeline-1.png" alt="CI/CD + SAST: Expectation vs Reality"><p></p><h2 id="expectation">Expectation</h2><p>Imagine, you set up your perfect DevSecOps pipeline.</p><p>&#x23E9;A developer pushes source code to a favorite source version control system,<br>&#x1F477;&#x200D;&#x2642;&#xFE0F; which activates a Continuous Integration (CI) pipeline<br>&#x1F52C; which starts security testing,<br>&#x1F9A0; then it finds a critical vulnerability,<br>&#x1F6D1; which, in turn, stops the entire pipeline and the developer goes fixing the issue.</p><p>Perfect, the security toolchain has just prevented a disaster! You have just saved the world (!) from releasing a vulnerable version of the product.</p><blockquote>The perfect outcome is to <strong>block</strong> the CI pipeline until addressing all the identified issues.</blockquote><h2 id="reality">Reality</h2><p>&#x1F528;You integrate a tool of your choice into the CI/CD pipeline,<br>&#x1F4DD; it gives you a ton of false positives,<br>&#x1F92F; you start triaging,<br>&#x1F92C; developers are irritated, they can&apos;t wait because the product release is scheduled &quot;for yesterday&quot;,<br>&#x1F612; you &quot;temporarily&quot; disable the integration until you can &#x1F9F9; clean up the security testing report,<br>&#x1F975; and it never ends.</p><p><strong>SAST </strong>means a <em>Static Application Security Testing</em> tool.</p><p>A security scan is usually required for Pull Request verification before merging the code or after the master branch commit. <strong>You don&apos;t want to pass the vulnerable code to the release.</strong></p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2022/01/you-shall-not-pass-1.gif" class="kg-image" alt="CI/CD + SAST: Expectation vs Reality" loading="lazy" width="498" height="203"></figure><p><strong>However</strong>,</p><ol><li>What if it finds 1000 false positives (wrong findings)?</li><li>What if takes 1 day to finish the analysis?</li><li>How does the tool decide that the detected vulnerability is critical?</li><li>How does it decide whether the finding is an actual vulnerability at all?</li><li>What are the criteria for stopping the pipeline?</li><li>How long does it take to analyze the code?</li></ol><h3 id="challenges">Challenges</h3><p>At the end of the day, it&apos;s often hard to deliver scan results in a <em>synchronous (blocking) </em>way.</p><p>I would say, there is a challenge of<strong> synchronous vs asynchronous</strong> security testing.</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2022/01/SAST-perfect-pipeline--zoom-in-.png" class="kg-image" alt="CI/CD + SAST: Expectation vs Reality" loading="lazy" width="643" height="515" srcset="https://fadeevab.com/content/images/size/w600/2022/01/SAST-perfect-pipeline--zoom-in-.png 600w, https://fadeevab.com/content/images/2022/01/SAST-perfect-pipeline--zoom-in-.png 643w"></figure><p><strong>Why </strong>it&apos;s often hard to deliver security scan results into CI/CD pipeline in a synchronous (blocking) way?</p><ol>
<li><strong>Legacy code with numerous issues</strong> (with a huge SAST output)
<ul>
<li>&#x201C;Unclean&#x201D; source code may result in a lot of security findings blocking a pipeline entirely until fixing/dismissing all the findings.</li>
</ul>
</li>
<li><strong>Scanning time</strong>
<ul>
<li>Different SAST tools have different efficiencies in terms of time and findings.</li>
<li>A huge code base may lead to <strong>slow scans</strong> (from 1 to a few hours).</li>
<li>What we also found is that on-the-cloud solutions usually have a little bit slower and/or unpredictable scan time (depending on the SLA of the vendor).</li>
</ul>
</li>
<li><strong>SAST tool limitations</strong>
<ul>
<li>Some tools have either rich or poor capabilities to report the scan result, e.g. a tool may have a true positive result having no means to report the scan result back immediately.</li>
<li>SAST tools may have specific requirements for the project structure and build steps.</li>
<li>Triaging: tools always generate false positives, there should be a way to conveniently fix and dismiss the security finding by a developer with<br>
cross-validation by a security specialist. The challenge is having a pipeline that <strong>supports the business</strong> (not completely blocking the business).</li>
</ul>
</li>
<li><strong>Budget compromises</strong>
<ul>
<li>There are sophisticated tools on the market, however, budget limitations may play a major role in what the team can afford.</li>
</ul>
</li>
<li><strong>Filtering commits</strong>
<ul>
<li>Scans usually run only for commits and PRs to master and release branches.</li>
</ul>
</li>
</ol>
<p></p><h2 id="solution">Solution</h2><h3 id="incremental-integration">Incremental Integration</h3><p>In practice, the solution here is to carry out a multi-stage SAST integration approach.</p><ol><li><strong>Stage 1: Baselining</strong><br>Tools are purchased, a source code is initially scanned, and false positives are reviewed/dismissed. Tickets are created, and vulnerabilities are fixed and submitted.</li><li><strong>Stage 2. Initial asynchronous integration</strong><br>SAST is integrated into a CI/CD pipeline, however, scan results don&#x2019;t block the pipeline (yet). The team executes an exercise of triaging and fixing the issues.</li><li><strong>Stage 3. Synchronous integration</strong><br>SAST blocks the pipeline in case of critical findings (according to the security policy). In the ideal scenario, a Jira ticket is automatically created.</li></ol><p>The last step is quite challenging because of false positives and because of all the challenges mentioned above. With some tools, e.g. <code>gosec</code> for Golang, synchronous integration is easily achieved and is the only way of dealing with the commit (the tool is very quick and doesn&#x2019;t produce a lot of output usually).</p><p>Having more sophisticated on-the-cloud tools (Coverity, Fortify-on-Demand, Veracode, etc.), we go with a hybrid model where we have <em>asynchronous </em>SAST scans for less critical projects, and <em>synchronous</em> scans in more critical cases wherever it&#x2019;s possible (if it is technically and organizationally possible).</p><h3 id="triage">Triage</h3><p>We have to come up with a few levels of <strong>issue severity</strong>. The simplest categorization is the following: </p><ol><li><strong>Severity 1 (Highest)</strong> implies the quickest mitigation and release (<em>1-2 days</em>) for the most critical issues. </li><li><strong>Severity 2 (Middle) </strong>means no direct impact and implies slower mitigation (say, <em>30 days</em>). </li><li><strong>Severity 3 (Lowest) </strong>with <em>3 months</em> for mitigation. </li></ol><p>Different classification schemes may use up to <em>5 severity types</em> implying different severity properties. </p><h3 id="release">Release</h3><p>There are<strong> 2 major</strong> <strong>conditions </strong>to pass the build to the release: </p><ol><li>All issues are fixed. </li><li>The security team manually allowed the release of an urgent hotfix. It happens that SAST considers minor findings as the major ones falsely. Usually, SAST tools provide an ability to pass the build with a dismissal comment by a security specialist (appsec, security lead) of why the build is allowed to be released.</li></ol><h2 id="summary">Summary</h2><p>Do integration of security tools incrementally in 3 stages: baselining, initial asynchronous integration, synchronous (blocking) integration. Triage issues semi-manually to get adapted to the tools of your choice. Work with teams, gain knowledge, and evolve with your system.</p>]]></content:encoded></item><item><title><![CDATA[Learn From Machines To Learn]]></title><description><![CDATA[My approach to exam preparation is like a machine learning approach.]]></description><link>https://fadeevab.com/learn-from-machines-to-learn/</link><guid isPermaLink="false">603c21b16438841071c4cca8</guid><category><![CDATA[Misc]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Thu, 13 Jan 2022 21:30:31 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2022/01/brain_charging-2.png" medium="image"/><content:encoded><![CDATA[<blockquote>I found this draft on the distant dusty shelves, and I publish it as it is. I created one after passing the CSSLP exam, thus it&apos;s a bit specific to CISSP/CSSLP exam preparation. However, the overall idea is applicable to any exam preparation.</blockquote><img src="https://fadeevab.com/content/images/2022/01/brain_charging-2.png" alt="Learn From Machines To Learn"><p>My approach to exam preparation is like a <em><strong>machine learning</strong></em> approach.</p><h3 id="what-does-it-mean">What does it mean?</h3><p>In the case of my <a href="https://fadeevab.com/the-shadow-of-csslp/">CSSLP preparation</a>, I had access to ~<strong>800 </strong>practice tests. (It is not too much in comparison to CISSP where I had ~<strong>4500 </strong>practice tests from a variety of resources).</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2022/01/1-ymAm5YO0KGG0pySGtTN_JQ.jpeg" class="kg-image" alt="Learn From Machines To Learn" loading="lazy" width="1400" height="933" srcset="https://fadeevab.com/content/images/size/w600/2022/01/1-ymAm5YO0KGG0pySGtTN_JQ.jpeg 600w, https://fadeevab.com/content/images/size/w1000/2022/01/1-ymAm5YO0KGG0pySGtTN_JQ.jpeg 1000w, https://fadeevab.com/content/images/2022/01/1-ymAm5YO0KGG0pySGtTN_JQ.jpeg 1400w" sizes="(min-width: 720px) 720px"></figure><h3 id="split-a-dataset-of-tests-into-3-major-parts">Split a dataset of tests into 3 major parts</h3><ol><li>One set of tests is to <strong>train </strong>your brain.&#x200C;&#x200C;<br>- For CSSLP I used <a href="https://hub.totalsem.com">Total Tester</a> which came with CSSLP All-in-One book.&#x200C;&#x200C;<br>- For CISSP I used the <a href="https://play.google.com/store/apps/details?id=com.learnzapp.wileycissp&amp;hl=en&amp;gl=US">Official (ISC)2 CISSP Study</a> application.</li><li>When you feel confident, try to get 80% of correct answers on some set of questions <strong>you never solved before</strong>. Thus, you <strong>validate </strong>your knowledge.&#x200C;&#x200C;<br>- I used the quiz from the (ISC)2 CSSLP CBK book.&#x200C;&#x200C;<br>- If you started with the CSSLP CBK book, then your validation dataset would be the questions from the CSSLP All-in-One book. And vice versa. You got the idea: you keep some questions in reserve and never touch them.</li><li>The <strong>test </strong>dataset is the exam itself.</li></ol><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2022/01/1-Nv2NNALuokZEcV6hYEHdGA.png" class="kg-image" alt="Learn From Machines To Learn" loading="lazy" width="776" height="185" srcset="https://fadeevab.com/content/images/size/w600/2022/01/1-Nv2NNALuokZEcV6hYEHdGA.png 600w, https://fadeevab.com/content/images/2022/01/1-Nv2NNALuokZEcV6hYEHdGA.png 776w" sizes="(min-width: 720px) 720px"><figcaption>Check this article for reference: <a href="https://towardsdatascience.com/train-validation-and-test-sets-72cb40cba9e7">https://towardsdatascience.com/train-validation-and-test-sets-72cb40cba9e7</a></figcaption></figure><p>Once you start to answer correctly on <strong>80%</strong> of the <strong>validation </strong>set of the questions, you are ready. (70% of successful answer rate is needed to pass (ISC)2 exams).</p><h3 id="how-many-questions-you-can-find-for-csslp">How many questions you can find for CSSLP</h3><ol><li>~150 test questions in the Official CSSLP CBK book.</li><li>~300 in the CSSLP All-in-One book.</li><li>350 in the Total Seminars Training Hub (the license comes with CSSLP All-in-One book).</li><li>&quot;Essential CSSLP Guide&quot; doesn&apos;t contain quiz questions.</li></ol><p>All in all, ~800 questions. Not too many.</p>]]></content:encoded></item><item><title><![CDATA[The Shadow of CSSLP]]></title><description><![CDATA[or "How I Passed CSSLP". My detailed feedback about preparation for CSSLP, study materials, training process, and passing CSSLP examination.]]></description><link>https://fadeevab.com/the-shadow-of-csslp/</link><guid isPermaLink="false">603242ef6438841071c4bf2d</guid><category><![CDATA[Security]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Sun, 14 Mar 2021 22:13:53 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2021/03/CSSLP_green-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://fadeevab.com/content/images/2021/03/CSSLP_green-1.jpg" alt="The Shadow of CSSLP"><p>CSSLP is a challenging <em>secure software lifecycle </em>certification.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.credly.com/badges/55b14206-1095-4a85-b118-a0cf9ec34a9b"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Certified Secure Software Lifecycle Professional (CSSLP) was issued by (ISC)&#xB2; to Alexander Fadeev.</div><div class="kg-bookmark-description">The vendor-neutral CSSLP credential validates that software professionals have the expertise to incorporate security practices &#x2013; authentication, authorization and auditing &#x2013; into each phase of the software development lifecycle, from software design and implementation to testing and deployment. CSSL&#x2026;</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">Credly</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.credly.com/images/5234a13b-f3e9-4bf3-b51c-3a4dbd56039a/linkedin_thumb_isc2_csslp.png" alt="The Shadow of CSSLP"></div></a></figure><p>I started my preparation right after <a href="https://fadeevab.com/cissp">becoming CISSP</a> while I was still warmed up. I tried to not lose momentum: it&apos;s the moment when you have memorized a lot, you are motivated, you&apos;re ready for tricky questions. And basically, the strategy paid off, in 2.5 months I&apos;ve got a new accomplishment. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2021/05/image.png" class="kg-image" alt="The Shadow of CSSLP" loading="lazy" width="1335" height="389" srcset="https://fadeevab.com/content/images/size/w600/2021/05/image.png 600w, https://fadeevab.com/content/images/size/w1000/2021/05/image.png 1000w, https://fadeevab.com/content/images/2021/05/image.png 1335w" sizes="(min-width: 720px) 720px"><figcaption>Seems like I&apos;m <a href="https://www.isc2.org/About/Member-Counts#accordion-0cefa8a36ca14029aad4bdb2f2b01a8e">the ONLY CSSLP</a> in Ukraine as for May 2021. &#x1F60E; &#x1F30D;</figcaption></figure><p>However, look at this picture. &#x1F447; Does it mean that CSSLP is probably &quot;smaller&quot; and easier than CISSP? Spoiler alert! NO.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2021/02/CISSP_CSSLP_books.jpg" class="kg-image" alt="The Shadow of CSSLP" loading="lazy" width="701" height="517" srcset="https://fadeevab.com/content/images/size/w600/2021/02/CISSP_CSSLP_books.jpg 600w, https://fadeevab.com/content/images/2021/02/CISSP_CSSLP_books.jpg 701w"><figcaption>CISSP is the boss of security certifications. But CSSLP is a small sneaky bastard which is gonna hurt you much.</figcaption></figure><p>The exam appeared to be very tough. At least it was not easier than <a href="https://fadeevab.com/cissp">CISSP</a>, even maybe harder.</p><p>The thing is that the smaller size of the knowledge base <em>does NOT mean that the questions on the exam will be easier</em>. Moreover, in my perception, the questions were even vaguer and trickier (not always for a good reason).</p><p>&#x1F4DD; CSSLP does not overlap very closely with CISSP in the knowledge base, I saw maybe ~1-2% of similar questions on the exam. Consider CSSLP as a completely separate exam which is &#x201C;an inch wide and a <strong>mile deep</strong>&#x201D;.</p><h2 id="lessons-learned">Lessons Learned</h2><p>It&apos;s not easy to find information about the format and content of the real examination. It is especially noteworthy compared to the richest amount of study materials and practice tests for the CISSP certification. Despite the fact there is a decent set of books and courses to study the theory, the lack of training materials can be the reason you might find CSSLP exam to be more difficult than the CISSP exam.</p><p><strong>Be mentally prepared</strong> for the fact that there will be questions you&apos;re not ready to answer with 100% of confidence.</p><p>Don&apos;t worry, it&apos;s okay if you get slightly shocked on the exam. Just focus, you are still able to pass.</p><p><strong>My experience </strong>helped me a lot. All in all, only experience can save your ass in the final battle. And that&apos;s why I appreciate my CSSLP achievement even more!</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2021/02/edge-of-tomorrow.gif" class="kg-image" alt="The Shadow of CSSLP" loading="lazy" width="400" height="163"></figure><h2 id="csslp-exam-overview">CSSLP Exam Overview</h2><p>I took the exam in February 2021, and it was of the following format:</p><ul><li>125 questions.</li><li>3 hours.</li><li>Multiple-choice (1 option to choose at a time).</li><li>You can&apos;t go back to the previous question.</li><li>It is not an adaptive examination (not a CAP), and you have to answer all 125 questions.</li></ul><p>The CSSLP exam has been shrunk to 125 questions. Funny thing is that I thought it became adaptive. This assumption made me nervous when the exam didn&apos;t stop on the 1o1st question. I lost my focus, and it could make me fail. Thankfully, I passed. Again, <strong>stay focused.</strong></p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2021/02/stay-focused-small.jpg" class="kg-image" alt="The Shadow of CSSLP" loading="lazy" width="437" height="292"></figure><ul><li>CSSLP is an &quot;<strong>English </strong>exam&quot;, like CISSP.&#x200C;&#x200C;<br>There are questions to find the <strong>BEST </strong>answer, and particularly, it means that many questions are formulated in some vague way (that sucks).<br>It will hurt those of you who are not native English speakers (like me) because sometimes there are questions where the answer is encoded into some synonym, and you probably see this word for the first time in your life, and your first step is to figure out what does the word mean in the context.</li><li>You are a <strong>manager</strong>.<br>Answering questions, imagine that you are a manager, not a strictly technical person. It means, for instance, that you have to prefer a risk assessment answer versus an option which implies immediate execution.</li><li>There are many questions (but not too many) about the knowledge of <strong>concepts </strong>and terms.&#x200C;&#x200C;<br>That&apos;s why I would suggest you NOT miss the theoretical part in your studying.</li></ul><h2 id="training-process">Training Process</h2><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2021/02/lofigirl-1.gif" class="kg-image" alt="The Shadow of CSSLP" loading="lazy" width="560" height="315"></figure><p><em>Every certification needs its own dedication and mental preparation</em>.<em> Your current knowledge and skills are needed. But it is not enough.</em></p><p>You MUST improve:</p><ol><li>Knowledge.</li><li>Mindset.</li></ol><!--kg-card-begin: markdown--><ol>
<li><strong>You need to get ready for the format of the examination.</strong><br>
Train your <strong>mindset</strong>. You will not find too much of insights related to the <strong>CSSLP</strong>, but you can find tips and tricks related to the other major (ISC)2 certification <strong>CISSP</strong>. Better yet, I would recommend preparing for the CISSP certification first, however, it&apos;s totally up to you. (It was my way though).
<ul>
<li>You need a mindset to <em><strong>quickly scan and understand questions</strong></em>.</li>
<li>You need to educate your <em><strong>inner voice</strong></em> to talk about <em><strong>every</strong></em> option. It helps a lot. Don&apos;t guess by particular words, rather try to utter every option inside of your mind, and explain why the option is correct, and why is not.</li>
</ul>
</li>
<li><strong>Read the books.</strong>
<ol>
<li>I started by reading <strong>&quot;CSSLP All-in-One Exam Guide&quot;</strong>, but <em>don&apos;t spend too much time on the final Chapters 18-20</em>, they are completely messy, unstructured, and they won&apos;t get you the knowledge to pass the exam.</li>
<li>Also, in my humble opinion, the <strong>&quot;Official (ISC2) Guide to the CSSLP CBK&quot;</strong> (2013) is much better: it is better structured, and it contains all the technical items you need to pass the exam. Just it&apos;s a bit too much <strong>bloated</strong>.</li>
<li>You can find an <strong>&quot;Essential CSSLP Exam Guide&quot;</strong> <strong>audiobook</strong> which could be a convenient source for your preparation. There is a unique structure by functional roles in the company, not by the domains. The contents is pretty unique and decent.<br>
&#x26A0;&#xFE0F; WARNING: I didn&apos;t use this book as the main source of knowledge in my preparation, I just went through a couple of freely available chapters. Therefore, I cannot assure you that you pass the exam just reading only this book.</li>
</ol>
</li>
<li><strong>Take practice tests.</strong><br>
I answered all questions after each chapter in &quot;CISSP All-in-One&quot;. They do <strong>not</strong> reproduce the format of the real questions but you don&apos;t have much choice. You need to practice.<br>
Then I used <a href="https://www.totalsem.com/store/csslp-totaltester/">CSSLP TotalTester</a> which contains <strong>350</strong> multiple-choice questions. You get the license key from the &quot;CSSLP All-In-One&quot; book. I have been practicing until I could get 78-80% pass rate.</li>
</ol>
<p>For reference, my pass rate by CSSLP All-in-One chapters:</p>
<table>
<thead>
<tr>
<th>Chapter</th>
<th>Pass Rate</th>
</tr>
</thead>
<tbody>
<tr>
<td>Chapter 1</td>
<td>100%</td>
</tr>
<tr>
<td>Chapter 2</td>
<td>100%</td>
</tr>
<tr>
<td>Chapter 3</td>
<td>93%</td>
</tr>
<tr>
<td>Chapter 4</td>
<td>73%</td>
</tr>
<tr>
<td>Chapter 5</td>
<td>86%</td>
</tr>
<tr>
<td>Chapter 6</td>
<td>66%</td>
</tr>
<tr>
<td>Chapter 7</td>
<td>80%</td>
</tr>
<tr>
<td>Chapter 8</td>
<td>73%</td>
</tr>
<tr>
<td>Chapter 9</td>
<td>80% (no prep.)</td>
</tr>
<tr>
<td>Chapter 10</td>
<td>66%</td>
</tr>
<tr>
<td>Chapter 11</td>
<td>80% (no prep.)</td>
</tr>
<tr>
<td>Chapter 12</td>
<td>66% (no prep.)</td>
</tr>
<tr>
<td>Chapter 13</td>
<td>73% (no prep.)</td>
</tr>
<tr>
<td>Chapter 14</td>
<td>80% (no prep.)</td>
</tr>
<tr>
<td>Chapter 15</td>
<td>80%</td>
</tr>
<tr>
<td>Chapter 16</td>
<td>80%</td>
</tr>
<tr>
<td>Chapter 17</td>
<td>86%</td>
</tr>
<tr>
<td>Chapter 18</td>
<td>73%</td>
</tr>
<tr>
<td>Chapter 19</td>
<td>66% (no prep.)</td>
</tr>
<tr>
<td>Chapter 20</td>
<td>skipped</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>&#x26A0;&#xFE0F; However, <a href="#bonus-be-careful-with-csslp-totaltester">be careful with CSSLP TotalTester</a> as well (see below). Besides of inconsistencies, it does not reflect what you&apos;re going to see on the real exam. Questions from the Official CBK book are much closer to what you&apos;ll get.</p><h3 id="validation-test-set">Validation Test Set</h3><p>Keep one set of questions till the end of your studying as a validation set. I used questions in the &quot;Official (ISC)2 Guide to the CSSLP CBK&quot;, which means that I never touched them until the very end of my preparation. By the way, &#xA0;I think the CBK book is the best source of the ultimate knowledge at the moment, even though the book hasn&apos;t been updated since 2013. The principles of secure software lifecycle are pretty universal and they have not been changed drastically for the last decade.</p><h3 id="video-courses">Video Courses</h3><p>Let me put some links on the video course here because video is the best way to bootstrap the knowledge about the domain.</p><p>&#x26A0;&#xFE0F; I didn&apos;t study by these video courses, they have appeared just around the time of my examination. Therefore, I can&apos;t guarantee their quality. Nonetheless, I used video courses at the beginning of my CISSP preparation, therefore I know that video can be quite helpful.</p><ul><li><a href="https://www.pluralsight.com/paths/csslpr-certified-secure-software-lifecycle-professional-2020">https://www.pluralsight.com/paths/csslpr-certified-secure-software-lifecycle-professional-2020</a></li><li><a href="https://www.linkedin.com/learning/search?keywords=csslp">https://www.linkedin.com/learning/search?keywords=csslp</a></li></ul><h2 id="problem-with-csslp-training-materials">Problem with CSSLP Training Materials</h2><p>I&apos;m still trying to correlate my feelings about passing the certification with the effectiveness of my training process.</p><p>CSSLP does not have the same level of consistency between a common body of knowledge and <strong>training materials</strong> compared to CISSP. There are inconsistencies between different books and practice tests, between the official guide, non-official books, and online practice tests.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2021/02/comparing_cissp_csslp_experience-1.png" class="kg-image" alt="The Shadow of CSSLP" loading="lazy" width="1471" height="953" srcset="https://fadeevab.com/content/images/size/w600/2021/02/comparing_cissp_csslp_experience-1.png 600w, https://fadeevab.com/content/images/size/w1000/2021/02/comparing_cissp_csslp_experience-1.png 1000w, https://fadeevab.com/content/images/2021/02/comparing_cissp_csslp_experience-1.png 1471w" sizes="(min-width: 720px) 720px"><figcaption>My pretty subjective evaluation of the quality of publicly available training material for CISSP and CSSLP (in 2020-2021).</figcaption></figure><p>I&apos;ve noticed a discrepancy in the concepts between CISSP and CSSLP, and my favorite one is the different definition of a <strong>data owner</strong> and a <strong>data custodian.</strong></p><ol><li>In CISSP a <em>data owner</em> defines the criteria of data classification <em>and</em> classifies the data, while implementation goes to a <em>data custodian.</em></li><li>In CSSLP a <em>data owner</em> defines criteria (only), whereas both <em>actions </em>of data classification and applying the controls refer to a <em>data custodian</em>.</li></ol><p>And you know what? I got exactly that question on the exam. I&apos;m still not sure whether my answer was correct.</p><p>Another problem is that there are not many practice tests in the wild. I calculated at most ~800 from all sources. In contrast, there are thousands and thousands of practice tests for CISSP. Consider, that it is believed that you need to answer at least 3000-5000 tests in order to get prepared for CISSP.</p><p>If CSSLP is your first exam, all that remains is to rely on your experience and your luck.</p><p><em>Train hard, fight easy. But what if there is no trainer, there is no fight concept, there is only your willingness, pictures in the book, and some experience &quot;from da streetz&quot;?</em></p><h3 id="beware-scam">Beware Scam</h3><ol><li>You can find many weak and bad CSSLP practice tests on the Internet. For instance, you know if your quiz is a scam if you find questions about <a href="https://en.wikipedia.org/wiki/Department_of_Defense_Information_Assurance_Certification_and_Accreditation_Process">DIACAP</a> there.</li><li>E.g. <a href="https://www.udemy.com/share/103z1sB0sbeFtVRHU=/">this course on Udemy</a> is not a real practice test for CSSLP.</li><li><a href="https://www.skillset.com/certifications/csslp">Skillset&apos;s practice exam</a> is pretty weak, the questions are loosely combined by CSSLP domain titles, and I think the test cases have been taken from other certification buckets. I don&apos;t recommend spending time and money on that.</li></ol><h2 id="still-you-can-do-it">Still, You Can Do It</h2><p>Mentally, just be ready for &quot;high entropy&quot;. Rely on your experience. Trust your knowledge. Be slow. You&apos;re a manager. Try to imagine the real situations. If you completely lost, don&apos;t panic! Stay focused!</p><p>And that&apos;s basically it. I hope my feedback can help you prepare better. You can do it! &#xA0;</p><hr><h2 id="bonus-be-careful-with-csslp-totaltester">Bonus: Be Careful With &quot;CSSLP TotalTester&quot;</h2><p>I spent plenty of time with <a href="https://www.totalsem.com/store/csslp-totaltester/">CSSLP TotalTester</a> online system, and I found a lot of discrepancies there. Here is my chart of the issues:</p><ol><li>There are multichoice tests in the sense that you have to select from 2 to 4 options simultaneously. I didn&apos;t see this approach on the exam. The good thing is that it trains your mind pretty well.</li><li>I found a question where RC4 marked as the best option to encrypt streaming video versus AES. RC4 cannot be an ultimate answer having AES in the list.</li><li>There is a question about risk <em>governance </em>(I cannot post the full question here), where the answer is supposed to be in the <em>governance </em>realm as well. Suddenly, risk <em>management</em> has been accepted as the correct answer. It&apos;s completely confusing because <em>governance</em> and <em>management </em>are different beasts.</li><li>One practice test assumed that source code analysis can be carried out on the <em>system level</em>. It is HOW? Tell me, how do you carry out source code analysis on the level of the system? A system is composed of subsystems, components, applications, interconnections, everything has been compiled (and there is source code on the components level) and integrated using different kinds of interfaces. Yes, I can reconstruct and evaluate the architecture by looking at the source code of separate components, but the &quot;source code of the overall system&quot; doesn&apos;t exist as a concept. Come on.</li><li>A question about risk management was answered with a &quot;risk analysis&quot; option, while the &quot;<em>risk management&quot; </em>option was declined with the reasoning that the question is about... risk management. &#x1F915; Don&apos;t try to understand it.</li><li>Sometimes there is a learning explanation, where the wording is meaningful, but the invalid option is marked as correct.</li><li>Vague wording, lack of detailed explanation (e.g. &quot;it&apos;s just wrong&quot; explanation of the accepted answer).</li></ol><hr><!--kg-card-begin: html--><iframe src="https://www.linkedin.com/embed/feed/update/urn:li:share:6775919541491965952" allowfullscreen title="Embedded post" width="504" height="840" frameborder="0"></iframe>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Cheat Sheet: Legal, Regulations, Compliance in Security]]></title><description><![CDATA[My cheat sheet I used to prepare for CISSP about how I understand and memorize legal and regulations in cybersecurity. I publish it because I use it, and you can use it too.]]></description><link>https://fadeevab.com/cheat-sheet-legal-regulations-compliance-in-security/</link><guid isPermaLink="false">602bd73b6438841071c4be6a</guid><category><![CDATA[Security]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Tue, 16 Feb 2021 15:01:21 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2021/02/photo-1507925921958-8a62f3d1a50d.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://fadeevab.com/content/images/2021/02/photo-1507925921958-8a62f3d1a50d.jpg" alt="Cheat Sheet: Legal, Regulations, Compliance in Security"><p>I wrote it quickly down during one of my ad-hoc conversations with a colleague. I had been preparing to <strong>CISSP </strong>that time, and I used it later in my preparations to <strong>CSSLP</strong>. From time to time, I come back to this cheat sheet. I decided to put it here for my and everyone&apos;s convenience. Enjoy!</p><!--kg-card-begin: markdown--><ol>
<li><strong>4th amendment</strong><br>
Nobody can be unreasonably seized and attacked by police.</li>
<li><strong>ECPA</strong><br>
No unwarranted wiretapping.</li>
<li><strong>PATRIOT Act</strong><br>
But if you&apos;re <em>maybe</em> Alcaida, then the CIA can wiretap you (without a warrant).</li>
<li><strong>CFAA</strong><br>
If you access any computer, you are a bad guy, you are committing a crime... If you made a loss of $5000 and higher, I can sue you.</li>
<li><strong>DMCA</strong><br>
If you violate copyright, you are committing a crime. It applies to reverse engineering as well. But if copyrighted data is at rest, or in transit via ISP facilities, ISP is not liable (but you are).</li>
<li><strong>SOX</strong><br>
It is a security of accounting of public companies.</li>
<li><strong>Privacy act of 1974</strong><br>
Federal agencies must protect PII of U.S. people.</li>
<li><strong>FISMA</strong><br>
Federal agencies must establish security according to NIST SP 800-53 controls.</li>
<li><strong>GLBA</strong><br>
Security of PFI (personal financial info). Annual &quot;Privacy Notice&quot; by email.</li>
</ol>
<!--kg-card-end: markdown--><hr><!--kg-card-begin: markdown--><ol>
<li><strong>PCI DSS</strong><br>
Credit card data touches your infrastructure? Take care about security and be compliant. More transactions and money - more fines if you fucked up.</li>
<li><strong>GDPR</strong><br>
Do you handle PII of European people? These people own their data. Be friendly and compliant!</li>
<li><strong>CCPA</strong><br>
Do you handle PII of California folks? Don&apos;t sell their data!.. Without concent.</li>
</ol>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[How I Passed CISSP]]></title><description><![CDATA[I have been awarded the CISSP certification! Here is how.]]></description><link>https://fadeevab.com/how-i-passed-cissp-november-2020/</link><guid isPermaLink="false">5ffdf58971d31e636c6f21db</guid><category><![CDATA[Security]]></category><category><![CDATA[Misc]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Sat, 16 Jan 2021 21:37:35 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2021/03/alexander-fadeev-cissp-fadeevab.com-1--2-.jpg" medium="image"/><content:encoded><![CDATA[<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.youracclaim.com/badges/3285dffc-5375-43bb-ba0b-18bce51e5f3c/public_url"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Certified Information Systems Security Professional (CISSP) was issued by (ISC)&#xB2; to Alexander Fadeev.</div><div class="kg-bookmark-description">The vendor-neutral CISSP credential confirms technical knowledge and experience to design, engineer, implement, and manage the overall security posture of an organization. Required by the world&#x2019;s most security-conscious organizations, CISSP is the gold-standard information security certification tha&#x2026;</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">Acclaim</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.youracclaim.com/images/5e6f5247-1d61-4932-a5da-999a7feec067/linkedin_thumb_isc2_cissp2.png" alt="How I Passed CISSP"></div></a></figure><img src="https://fadeevab.com/content/images/2021/03/alexander-fadeev-cissp-fadeevab.com-1--2-.jpg" alt="How I Passed CISSP"><p>UPDATE: I also encourage you to read my write-up about of how I passed CSSLP (after CISSP), there are even more details about my training process and study approach: <a href="https://fadeevab.com/the-shadow-of-csslp/">The Shadow of CSSLP</a>.</p><h2 id="short-formula">Short Formula</h2><p><code>knowledge</code> + <code>mindset</code> + <code>dedication</code> = <code>success</code></p><h2 id="intro">Intro</h2><p>I started somewhere in 2015 with just reading the book &quot;CISSP All-in-One Exam Guide&quot; (Sixth Edition, Shon Harris), and my English level didn&apos;t allow me to move quickly, I had to improve my vocabulary, reading, writing, listening. I didn&apos;t force my studying, I decided to make an overall review of all domains in to get back later with a more conscious approach to study. After a while, I dropped reading for a couple of years, and I concentrated on earning real practical experience in cybersecurity which is 14 years as of 2021.</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2021/02/CISSP-Preparation-of-Alexander-Fadeev-Infographics.png" class="kg-image" alt="How I Passed CISSP" loading="lazy" width="1294" height="406" srcset="https://fadeevab.com/content/images/size/w600/2021/02/CISSP-Preparation-of-Alexander-Fadeev-Infographics.png 600w, https://fadeevab.com/content/images/size/w1000/2021/02/CISSP-Preparation-of-Alexander-Fadeev-Infographics.png 1000w, https://fadeevab.com/content/images/2021/02/CISSP-Preparation-of-Alexander-Fadeev-Infographics.png 1294w" sizes="(min-width: 720px) 720px"></figure><p><br>Basically, I don&apos;t feel that having experience in 3 of 8 domains is really enough to be confident to step up the CISSP certification. I think that CISSP is more prone to corporate security, and in my case, I had many years in R&amp;D (development in security), where you&apos;re pretty close to technicalities, but far from things like security governance, operations, access controls, etc. In 2019 I got the application security position in a company, where corporate security is the biggest challenge, and I gained exactly that experience what CISSP stands for.</p><p>At some point I just realized that I&apos;m ready, it was October 2o2o, I just needed to prove that I am who I am. I started my dedicated preparation: 2 hours every morning (books, video courses), then I added 2 hours in the evening, then I couldn&apos;t stop and spent 6-8 hours per day, especially on the weekend, and in the end, I was spending the whole weekend in the study.<br><br>Books, video courses, 4500 practical test questions during 2 months.</p><h2 id="short-advice">Short Advice</h2><ol><li><strong>Create a plan</strong> for preparation. It&apos;s easy. For example, you want to watch 10 hours of video courses and you&apos;d like to spend 10 additional hours to learn the contents of the video, therefore you need 10 days (~2 weeks) if you spend 2 hours per day for preparation.</li><li><strong>Set up a schedule</strong> in your calendar for every single day. <strong>Just do it</strong>: go to your <strong>calendar </strong>right now, and make an appointment for every day.</li><li>You will need to answer <strong>from 4000 to 5000 practical questions </strong>where you get <strong>~80%</strong> of correct answers. How much time would you need? 200 questions per day = 20 additional day days of preparation. Not too much! :)</li><li><code>exam preparation</code> != <code>knowledge</code> != <code>real-life experience</code>. It&apos;s all different. You need to <em>concentrate </em>at maximum in the process of your preparation to get ready for the examination.</li></ol><h2 id="study-materials">Study Materials</h2><p>All in all, I feel that all study materials contain incomplete but complementary knowledge, something like this:</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2021/01/CISSP-Study-Material-3.png" class="kg-image" alt="How I Passed CISSP" loading="lazy" width="544" height="582"></figure><!--kg-card-begin: markdown--><ol>
<li>Initially, I bought CISSP Certification <strong>video courses</strong> by <strong>Thor Pedersen</strong> on Udemy <em>(8 courses per ~$16)</em>, and at the end of my studying, I found all those courses cheaper on his personal website <a href="https://thorteaches.com/">https://thorteaches.com/</a>. And because I also purchased &quot;Boson&quot; tests later for ~$99 (see below), it would be cheaper to just go to <a href="https://thorteaches.com/">https://thorteaches.com/</a> and buy there &quot;CISSP Bundle + Boson&quot; for <strong>~$175</strong> (Thor&apos;s videos + Boson tests). Arithmetics is simple: <code>$175 &lt; 8 * $16 + $99</code>. And now I don&apos;t get any referrals from this guy, I just want you to save a couple of bucks.</li>
<li>In the case if you prefer learning on Udemy I put all links here:
<ol>
<li><a href="https://www.udemy.com/course/cissp-domain-1-2/">CISSP Domain 1-2</a>.</li>
<li><a href="https://www.udemy.com/course/cissp-domain-3-4/">CISSP Domain 3-4</a>.</li>
<li><a href="https://www.udemy.com/course/cissp-domain-5-6/">CISSP Domain 5-6</a>.</li>
<li><a href="https://www.udemy.com/course/cissp-domain-7-8/">CISSP Domain 7-8</a>.</li>
<li><a href="https://www.udemy.com/course/cissp-certification-practice-exam-1/">250 questions of CISSP practice exam #1</a>.</li>
<li><a href="https://www.udemy.com/course/cissp-certification-practice-exam-2/">250 questions of CISSP practice exam #2</a>.</li>
<li><a href="https://www.udemy.com/course/cissp-certification-practice-exam-3/">250 questions of CISSP practice exam #3</a>.</li>
<li><a href="https://www.udemy.com/course/cissp-certification-practice-exam-4/">250 questions of CISSP practice exam #4</a>.</li>
</ol>
</li>
<li><strong>Install <a href="http://www.learnzapp.com/apps/cissp-tests/index.html">(ISC)2 Official CISSP Tests</a></strong> on your phone. Run &quot;Quick Test&quot; (10 questions) periodically every day, &quot;Mock Test&quot; (50 questions), and &quot;Practice Test&quot; (125 questions) whenever you wish.</li>
<li><strong>Install Boson&apos;s</strong> test kit <strong><a href="https://boson.com/practice-exam/cissp-isc2-practice-exam">&quot;ExSim-Max for CISSP 2020&quot;</a></strong> (<strong>$99</strong>). There are 5 test sets (as for 2020), use them to finalize your preparation. Don&apos;t solve them all in the beginning, keep a couple of test sets to double-check your readiness later.</li>
<li>I won&apos;t recommend to <em>start</em> from &quot;<strong>CISSP All-In-One Exam Guide</strong>&quot;, but I can&apos;t change my past where it helped me to discover CISSP, and later to dive into particular details of most of security domains, though there is a lot of outdated information which would not be necessary to dedicatedly learn in order to pass the exam. I answered <em><strong>practical questions</strong></em> at the end of each chapter and at the end of the book. The questions are really hardcore there, but they shake your mind pretty badly.</li>
<li>&quot;<strong>CISSP Practice Exams</strong>&quot; (by Shon Harris) was on my table as well, and I used it to train practice question of several CISSP domains (no all of them though).</li>
<li>There are resources that I didn&apos;t use in my preparation, but many people recommended:
<ul>
<li><strong>&quot;CISSP Study Guide&quot;</strong> (by Eric Conrad) is a very appreciated and highly recommended book, but <em>I didn&apos;t read it</em>.</li>
<li><strong>&quot;The Official (ISC)2 Guide to the CISSP CBK Reference&quot;</strong> is an official reference to CISSP CBK (Common Body of Knowledge). I used (ISC)2 Official CISSP Tests and Boson test kit instead of official CBK.</li>
</ul>
</li>
</ol>
<!--kg-card-end: markdown--><h2 id="how-i-figured-out-that-i-m-ready">How I Figured Out That I&apos;m Ready</h2><p>It was Thursday&apos;s evening, and I felt that I&apos;m fed up with preparation.</p><p>It&apos;s kind of &quot;enough&quot; code in my head.</p><p>I decided to solve Boson&apos;s quiz to check whether I&apos;m ready. The goal was to pass the test exam with the ~80% rate. I passed. And in the next minute, I entered <a href="https://home.pearsonvue.com/isc2">Pearson Vue (ISC)2</a> and scheduled my exam for the next morning.</p><h2 id="exam-day">Exam Day</h2><p>I took a taxi and arrived at a PearsonVue test center half an hour before the exam. Questions were crazy. There were questions when I had no idea about what they are. Just imagine my feelings, when after processing tons of information over the years of work and through the course of studying, you still see something for the first time on the exam.</p><p>There were questions, when I had to write down some calculations to figure out the right answer. Overall, it was hard to say whether I win, or I fail.</p><p>Later, I found the official <a href="https://www.isc2.org/Certifications/CISSP/CISSP-CAT#">CISSP Computerized Adaptive Testing (CAT) FAQ</a>, and I felt exactly what described there:</p><blockquote>Consequently, many candidates will feel that they did poorly on the exam as all candidates are expected to only get 50% of items they answer correct. This psychological phenomenon is common for CAT exam candidates, as most fixed-forms exams have candidates answer a higher proportion of items correctly due to item targeting inefficiencies. It is important for a candidate to remember it is not the number of items answered correct that is important, everyone will get about 50% correct, it is the difficulty of the items that he/she answer correct which is relevant for passing the exam.</blockquote><p>I passed the exam on the <strong>100th question</strong>, BUT I hadn&apos;t received my result immediately in that PearsonVue center for some reason, so I had to go back home, and check the result in my PearsonVue account.</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2021/01/image.png" class="kg-image" alt="How I Passed CISSP" loading="lazy" width="1417" height="257" srcset="https://fadeevab.com/content/images/size/w600/2021/01/image.png 600w, https://fadeevab.com/content/images/size/w1000/2021/01/image.png 1000w, https://fadeevab.com/content/images/2021/01/image.png 1417w" sizes="(min-width: 720px) 720px"></figure><p>I received the official &quot;pass&quot; result in the evening.</p><p>CISSP is an English exam. In most questions, you can feel that 4 of 4 answers have a chance to be correct, yet there are tiny differences that you learn to identify through the course of your preparation (e.g. prefer risk-based approach and cut off any unclear answer).</p><p>The funny thing is that because I&apos;m not a native English speaker, I just forgot whether &quot;pass&quot; means &quot;good&quot;, or &quot;bad&quot;, therefore I was pretty nervous until I got the official result on my mailbox. This is because in my native language we say &quot;passed successfully&quot;, or &quot;passed unsuccessfully&quot;, instead of &quot;passed&quot;, or &quot;failed&quot; in English. So, if you worry, just know that &quot;pass&quot; means &quot;good&quot;, and &quot;fail&quot; means... you know, it means that you have to try harder. ;)</p><h2 id="what-s-next">What&apos;s Next?</h2><p>I don&apos;t want to spend too much time on certifications, the thing is to apply knowledge, protect the common good. I&apos;d like to pass CSSLP to showcase my secure software lifecycle experience, and I know that it&apos;s better to not lose the momentum after passing the first exam. </p><p>In the end, let me recall my own words from my <a href="https://www.linkedin.com/embed/feed/update/urn:li:share:6743925072211304448">LinkedIn post</a>:</p><blockquote>I often forget, I often disbelieve that if to put effort, motivation, and determination, you can achieve good results, and it will always remind me to not forget, and to believe in myself.</blockquote><!--kg-card-begin: html--><iframe src="https://www.linkedin.com/embed/feed/update/urn:li:share:6743925072211304448" allowfullscreen title="Embedded post" width="504" height="612" frameborder="0"></iframe><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[💉 Decrypt iOS Applications: 3 Methods]]></title><description><![CDATA[You will learn how to decrypt and dump an iOS application with 3 different tools. As a bonus: how to jailbreak iPhone (see in the annex).]]></description><link>https://fadeevab.com/decrypt-ios-applications-3-methods/</link><guid isPermaLink="false">5d5bfe290d4ea976b0edd334</guid><category><![CDATA[Development]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Fri, 25 Sep 2020 21:12:59 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2020/09/ios-decrypt-and-dump.png" medium="image"/><content:encoded><![CDATA[<h2 id="scenario">Scenario</h2><img src="https://fadeevab.com/content/images/2020/09/ios-decrypt-and-dump.png" alt="&#x1F489; Decrypt iOS Applications: 3 Methods"><p><code>jailbreak</code> -&gt; <code>select tool</code> -&gt; <code>dump</code></p><h2 id="instruments">Instruments</h2><p>You have 3 options:</p><ol><li><a href="https://github.com/AloneMonkey/frida-ios-dump">frida-ios-decrypt</a> (jump to <a href="#how-to-use-frida-ios-decrypt">How to Use &quot;frida-ios-decrypt</a>&quot;)</li><li><a href="https://github.com/KJCracks/Clutch">Clutch</a> (jump to <a href="#how-to-use-clutch">How to Use &quot;Clutch&quot;</a>)</li><li><a href="https://github.com/AloneMonkey/dumpdecrypted">dumpdecrypted.dylib</a> (jump to <a href="#how-to-use-dumpdecrypted-dylib">How to Use &quot;dumpdecrypted.dylib&quot;</a>)</li></ol><p>Additionally, you need SSH (OpenSSH) installed on a jailbroken iPhone to be able to copy dumped files.</p><h2 id="overview">Overview</h2><p>An application from Apple App Store is encrypted with a hardware-backed cryptographic scheme. More precisely, an executable section of the O-Mach binary inside the IPA package is encrypted, and the decryption key is accessible only on a particular device on the hardware level (Secure Enclave). But if you wonder whether it is possible to decipher an application downloaded from Apple App Store to carry out static analysis - yes, it is possible.</p><p>In the annex, you can find <a href="#how-to-jailbreak-iphone-12-x">How To Jailbreak iPhone 12.x</a> and <a href="#how-to-fix-entitlements">How to Fix Entitlements</a>.</p><h2 id="how-tools-work">How Tools Work</h2><p>All tools leverage a simple principle: these tools dump a <strong>decrypted </strong>binary from the <strong>running</strong> context in the memory. It is possible because the binary MUST be decrypted before it could be even run, and the binary is dumped into a file.</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2019/08/iOsAppDecryptAndDump.png" class="kg-image" alt="&#x1F489; Decrypt iOS Applications: 3 Methods" loading="lazy"></figure><p>You MUST <strong>jailbreak iPhone</strong> to dump decrypted executable region to the filesystem. There is<em> no way to easily decrypt an application by any kind of magic tool on a personal computer</em>.</p><p>There are 2 approaches to dump deciphered executable region from memory to the filesystem. All of them require superuser privileges either to <em>trace a process</em>, or to <em>inject a dynamic library</em>.</p><h3 id="approach-1-attach-to-a-process">Approach #1: attach to a process</h3><p><a href="https://github.com/KJCracks/Clutch">Clutch</a> and <a href="https://github.com/AloneMonkey/frida-ios-dump">frida-ios-decrypt</a> work this way.</p><ol><li>The tool (<em>tracer</em>) attaches to a running process (<em>tracee</em>).</li><li>The deciphered executable is dumped from the memory into a file.</li></ol><p>Step 1 (tracing the process) needs superuser privileges, that&apos;s why iPhone must be jailbroken.</p><h3 id="approach-2-library-injection">Approach #2: library injection </h3><p><a href="https://fadeevab.com/p/fb64a114-cbad-4634-afef-19c106aa183d/dumpdecrypted.dylib">dumpdecrypted.dylib</a> works this way (through DYLD_INSERT_LIBRARIES).</p><ol><li>An application starts with a dynamic library linked into it.</li><li>The dynamic library dumps decrypted executable right from the application user space memory.</li></ol><p>Superuser privilege is needed to inject a custom dynamic library into the process memory.</p><h2 id="how-to-use-frida-ios-decrypt">How to Use &quot;frida-ios-decrypt&quot;</h2><h3 id="prepare-usb-and-ssh">Prepare USB and SSH</h3><p>The main script of &quot;frida-ios-decrypt&quot; <code>dump.py</code> uses the <code>frida</code> package which communicates with the device via <strong>USB</strong>. When the application is successfully dumped, files will have been copied from the device via <strong>SSH</strong> (<code>scp</code>) to the temporary folder. To summarize, your iPhone must be accessible via both USB and SSH.</p><p>An official guide suggests to set up <em>SSH over USB</em>, but that way seems to be a bit complicated. I found the easier way which is to connect an iPhone to your local network (connect to the same WiFi network) and modify <code>dump.py</code> as the following to allow the script to connect to the phone directly over your local network:</p><pre><code class="language-python">User = &apos;root&apos;
Password = &apos;alpine&apos;
Host = &apos;192.168.88.102&apos; # Fix the Host IP to a real iPhone IP
Port = 22
</code></pre><!--kg-card-begin: markdown--><h3 id="steps">Steps</h3>
<ol>
<li>Follow the <a href="https://github.com/AloneMonkey/frida-ios-dump/">frida-ios-dump installation guide</a>.</li>
<li><code>frida-ios-dump</code> looks for a device using SSH. Use &quot;SSH over USB&quot; approach, or connect your device to a local network and fix <code>dump.py</code> (see Preparation above).</li>
<li>List running processes:<pre><code class="language-bash">python2 ./frida-ios-dump-master/dump.py -l
</code></pre>
</li>
<li>Dump the target process:<pre><code class="language-bash">python2 ./frida-ios-dump-master/dump.py &quot;TargetApp&quot;
</code></pre>
or<pre><code class="language-bash">python2 ./frida-ios-dump-master/dump.py &lt;pid&gt;
</code></pre>
</li>
</ol>
<h3 id="successfullog">Successful log</h3>
<pre><code>Start the target app TargetApp
Dumping TargetApp to /some/temp/path
[frida-ios-dump]: libswiftUIKit.dylib has been dlopen.
[frida-ios-dump]: libswiftIntents.dylib has been dlopen.
[frida-ios-dump]: libswiftCoreImage.dylib has been dlopen.
...
...A lot of noisy log may follow here
...
Generating &quot;TargetApp.ipa&quot;
</code></pre>
<!--kg-card-end: markdown--><h3 id="troubleshooting">Troubleshooting</h3><h4 id="device-is-not-found-via-usb">Device is not found via USB</h4><pre><code>Waiting for USB device...</code></pre><p>Ensure that you installed USB drivers for iPhone.</p><p>Also, if you&apos;re on Windows Subsystem for Linux (WSL), you would be unable to run &quot;frida-ios-dump&quot;, because there is no USB drivers for iPhone under WSL, therefore iPhone cannot be enumerated. (Not sure about WSL 2 though).</p><h4 id="device-is-not-found-via-ssh">Device is not found via SSH</h4><p>Either way, if <code>dump.py</code> cannot connect to a device, you will see the following error:</p><pre><code>*** Caught exception: &lt;class &apos;socket.error&apos;&gt;: [Errno 11] Resource temporarily unavailable</code></pre><p>or</p><pre><code>*** Caught exception: &lt;class &apos;socket.error&apos;&gt;: [Errno 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond</code></pre><p>Check whether you use a correct IP address in <code>dump.py</code> for your iPhone.</p><ol><li>On iPhone: go to Settings -&gt; WiFi -&gt; (i) -&gt; get the IP.</li><li>Verify the connection:<code>ssh root@192.168.88.101</code></li><li>Password: <strong>alpine</strong></li></ol><h2 id="how-to-use-clutch">How to Use &quot;Clutch&quot;</h2><p>IMPORTANT: On iPhone 12.x you need to <a href="#how-to-fix-entitlements">fix entitlements &#x2B07;&#xFE0F;</a>.</p><!--kg-card-begin: markdown--><ol>
<li>Build and install the <a href>Clutch</a> tool.</li>
<li>List the processes:<pre><code class="language-bash">Clutch -i
</code></pre>
</li>
<li>Dump the process obtaining decrypted binaries:<pre><code class="language-bash">Clutch -d 3
</code></pre>
&quot;3&quot; is the number of the application from the <code>Clutch -i</code> output.</li>
</ol>
<!--kg-card-end: markdown--><h2 id="how-to-use-dumpdecrypted-dylib">How to Use &quot;dumpdecrypted.dylib&quot;</h2><p>IMPORTANT: On iPhone 12.x you need to <a href="#how-to-fix-entitlements">fix entitlements </a>&#x27A1;&#xFE0F;<a href="#how-to-fix-entitlements">&#xFE0F;</a>.</p><!--kg-card-begin: markdown--><ol>
<li>Download <a href="https://github.com/AloneMonkey/dumpdecrypted">dumpdecrypted.dylib</a> to a computer.</li>
<li>Copy <code>dumpdecrypted.dylib</code> to the system path on the phone via SSH using <code>scp</code> tool:<pre><code class="language-bash">scp dumpdecrypted.dylib root@192.168.88.101:/usr/lib/dumpdecrypted.dylib
</code></pre>
Choose a path, kind of <code>/usr/lib</code>, not <code>$HOME</code>, to evade problems with kernel sandboxing.</li>
<li>Run the application with <code>dumpdecrypted.dylib</code>:<pre><code class="language-bash">DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Containers/Bundle/Application/BFED82A3-3238-4F41-B797-C1CB584CBE05/targetapp/targetapp
</code></pre>
</li>
</ol>
<!--kg-card-end: markdown--><hr><h2 id="how-to-jailbreak-iphone-12-x">How to Jailbreak iPhone 12.x</h2><!--kg-card-begin: markdown--><ol>
<li>Download <a href="https://chimera.sh">Chimera IPA package</a>.</li>
<li>Download <a href="http://www.cydiaimpactor.com">Cydia Impactor</a>.</li>
<li>Deploy Chimera package to iPhone using the Cydia tool (it will ask your Apple ID, it can be ANY free Apple ID).<br>
<img src="https://fadeevab.com/content/images/2019/08/UsingCydiaToInstallAnyPackage-1.png" alt="&#x1F489; Decrypt iOS Applications: 3 Methods" loading="lazy"></li>
<li>On the iPhone: go to the Chimera and press a button &quot;Jailbreak&quot;.<br>
<img src="https://fadeevab.com/content/images/2019/08/ChimeraJailbreak-1.PNG" alt="&#x1F489; Decrypt iOS Applications: 3 Methods" loading="lazy"></li>
</ol>
<!--kg-card-end: markdown--><p><strong>Sileo marketplace </strong>app appears after the jailbreak is installed.</p><ol><li>Go to the Sileo application.</li><li>Find and install <strong>Frida</strong> and <strong>OpenSSH (sshd).</strong></li></ol><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fadeevab.com/content/images/2019/08/SileoOpenSshInstall-1.PNG" class="kg-image" alt="&#x1F489; Decrypt iOS Applications: 3 Methods" loading="lazy"><figcaption>Install OpenSSH in the Sileo application</figcaption></figure><h2 id="how-to-fix-entitlements">How to Fix Entitlements</h2><p>The big advantage of &quot;frida-ios-dump&quot; against the &quot;Clutch&quot; and &quot;dumpdecrypt.dylib&quot; is that it doesn&apos;t need to fix entitlements of the target app.</p><p>Entitlements are special properties assigned to each application in iOS. Entitlements are signed and basically, it&apos;s not possible to change them without a jailbreak.</p><p><em><strong>In iOS 12.x default entitlements of application don&apos;t allow tracing.</strong></em> In the case of <code>Clutch</code> you are going to see the following error:</p><pre><code>Could not obtain mach port, either the process is dead (codesign error?) or entitlements were not properly signed!
</code></pre><h4 id="steps-to-fix-entitlements-">Steps to fix entitlements:</h4><!--kg-card-begin: markdown--><ol>
<li>Dump the current entitlements of the target application:<pre><code class="language-bash">ldid -e /var/containers/Bundle/Application/F8809B92-7794-4540-A4E2-0F541D78CF5A/TaretApp.app/TargetApp &gt; ~/targetapp-ent.xml
</code></pre>
</li>
<li>Fix entitlements adding the following line to <code>targetapp-ent.xml</code>:<pre><code class="language-xml">&lt;key&gt;platform-application&lt;/key&gt;
&lt;true/&gt;
&lt;key&gt;get-task-allow&lt;/key&gt;
&lt;true/&gt;
&lt;key&gt;run-unsigned-code&lt;/key&gt;
&lt;true/&gt;
&lt;key&gt;com.apple.private.skip-library-validation&lt;/key&gt;
&lt;true/&gt;
&lt;key&gt;com.apple.private.security.no-container&lt;/key&gt;
&lt;true/&gt;
</code></pre>
</li>
<li>Assign new entitlements:<pre><code class="language-bash">ldid -S~/targetapp-ent.xml /var/containers/Bundle/Application/F8809B92-7794-4540-A4E2-0F541D78CF5A/TargetApp.app/TargetApp
</code></pre>
</li>
</ol>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Half Full or Half Empty Glass of Cybersecurity]]></title><description><![CDATA[And what is your glass of cybersecurity? (Image)]]></description><link>https://fadeevab.com/half-full-or-half-empty-glass-of-cybersecurity/</link><guid isPermaLink="false">5eb53935c2b78640abcf8950</guid><category><![CDATA[Security]]></category><category><![CDATA[Misc]]></category><dc:creator><![CDATA[Alexandr Fadeev]]></dc:creator><pubDate>Fri, 08 May 2020 11:22:34 GMT</pubDate><media:content url="https://fadeevab.com/content/images/2020/05/Half-Full-or-Half-Empty-Glass-of-Cybersecurity-fadeevab.com-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://fadeevab.com/content/images/2020/05/Half-Full-or-Half-Empty-Glass-of-Cybersecurity-fadeevab.com-1.jpg" alt="Half Full or Half Empty Glass of Cybersecurity"><p>Sometimes I feel like my half full glass is fighting &#x2694;&#xFE0F; with a half empty one. So I drew this picture to visualize that idea &#x1F642;</p><p>And what is your glass of cybersecurity? Everything can be hacked or everything can be protected?</p><figure class="kg-card kg-image-card"><img src="https://fadeevab.com/content/images/2020/05/Half-Full-or-Half-Empty-Glass-of-Cybersecurity-fadeevab.com.jpg" class="kg-image" alt="Half Full or Half Empty Glass of Cybersecurity" loading="lazy"></figure>]]></content:encoded></item></channel></rss>