<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://sdsdkkk.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sdsdkkk.github.io/" rel="alternate" type="text/html" /><updated>2026-02-25T01:57:44+00:00</updated><id>https://sdsdkkk.github.io/feed.xml</id><title type="html">Edwin Tunggawan</title><subtitle>Thoughts on various stuff, mostly software engineering and cybersecurity</subtitle><author><name>Edwin Tunggawan</name><email>vcc.edwint@gmail.com</email></author><entry><title type="html">AntiHackerlink Hacking Artifact from 2003</title><link href="https://sdsdkkk.github.io/2026-02-24/antihackerlink-hacking-artifact-from-2003" rel="alternate" type="text/html" title="AntiHackerlink Hacking Artifact from 2003" /><published>2026-02-24T00:00:00+00:00</published><updated>2026-02-24T00:00:00+00:00</updated><id>https://sdsdkkk.github.io/2026-02-24/antihackerlink-hacking-artifact-from-2003</id><content type="html" xml:base="https://sdsdkkk.github.io/2026-02-24/antihackerlink-hacking-artifact-from-2003"><![CDATA[<p>It’s not really a secret that among Indonesian tech company founders, Wenas Agusetiawan and Juny Maimun have a legendary status in the underground hacking communities especially in the 1990s and the 2000s.</p>

<p>In 2000, Wenas Agusetiawan was <a href="https://data.tempo.co/MajalahTeks/detail/ARM20180612121540/hacker-indonesia-tertangkap-di-singapura">arrested for unauthorized network intrusion</a> into NUS’ network. He was active under the handle <code class="language-plaintext highlighter-rouge">hC-</code> (short for “Hantu Crew” where “hantu” is an Indonesian word for “ghost”), <a href="https://id.wikibooks.org/wiki/Sejarah_Internet_Indonesia/Juli_2000_hC_di_adili_di_Singapura">as mentioned in this Wikibooks page</a>.</p>

<p>Juny Maimun (more commonly referred to as Acong) was also <a href="https://www.viva.co.id/arsip/130394-acong-hacker-insaf-yang-suka-berbagi">covered by a news site</a> in 2010 as a hacker who already got into countless of servers, using <code class="language-plaintext highlighter-rouge">bagan</code> as his hacker handle.</p>

<p>Wenas Agusetiawan is now primarily known as <a href="https://rocketreach.co/wenas-agusetiawan-email_442071">one of the co-founders of Tiket.com</a>, a major Indonesian online travel agent. Meanwhile, Juny Maimun is primarily known as <a href="https://www.viva.co.id/arsip/130394-acong-hacker-insaf-yang-suka-berbagi">the founder of Indowebster and Maxindo</a>. Indowebster used to be a popular online forum in Indonesia back in the 2000s and early 2010s, and Maxindo is an ISP.</p>

<p>Both of them used to be in a local underground hacking group called AntiHackerlink, and they used to hang out in an IRC channel called <code class="language-plaintext highlighter-rouge">#antihackerlink</code> on <a href="https://www.dal.net/">DALnet IRC</a>.</p>

<p>I don’t have any personal ties with them, aside from having the opportunity to meet Juny Maimun once in 2012 where he was together with the late Arif Wicaksono, another AntiHackerlink member known with the handle <code class="language-plaintext highlighter-rouge">sakitjiwa</code> (which means “mental illness” in English). But one of the people who taught me cybersecurity (and mentored me in many ways) used to hang out in the same underground community as them. I’m not going to name the person here since they never even mentioned the name of AntiHackerlink community or the handle they used during their illegal hacking days (I think I might have figured it out already though).</p>

<p>What I meant to do in this post is to document a hack by AntiHackerlink in 2003, as I happened to stumble upon an evidence of the hack happening in <a href="https://marc.info/?l=incidents&amp;m=104198322804808&amp;w=2">an old mailing list archive</a>.</p>

<p>The following is the full text of the archived message.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>List:       incidents
Subject:    Re: Possible google hack
From:       &lt;rsavage () nandomedia ! com&gt;
Date:       2003-01-07 22:28:37
[Download RAW message or body]

Your proxy was probably hacked, not google's.

-- 
Rory Savage, Senior Systems Administrator
Nando Media: www.nandomedia.com
email: rsavage@nandomedia.com
aol im (PiasElihU)
919-836-5987 (Office)



On Tue, 7 Jan 2003, Johnson, April wrote:

&gt; I've run into something most unusual in my proxy cache from last night: This
&gt; was what appeared if I used my proxy to view www.google.com. It *could* be
&gt; that my proxy cache was hacked, or some kind of dns spoofing/corruption
&gt; occured between here and there.  But has anyone else heard/seen this?
&gt; 
&gt; Ping for www.google.com resolves to 216.239.33.101 - from the proxy console.
&gt; 
&gt; The google site with a black background and the text
&gt; 
&gt; Touch by cassablanca
&gt; 
&gt; 
&gt; Gratz To
&gt; 
&gt; s2c botaks [M2C] Junkist DewaLangit SpaceGhostz Ghostz bagan Escuver
&gt; frozenghost Gir4ff3 AxAL
&gt; 
&gt; #IndoHackerLInk@DAL.Net  #AntiHackerLink@DAL.Net #RealCyber@DAL.net
&gt; 
&gt; 
&gt; I've included the source as follows... It doesn't look all that clean.
&gt; 
&gt; 
&gt; -April Johnson (CISSP, MCSE, CCNP)
&gt; Network Operations - Security
&gt; Seattle Public Schools
&gt; apjohnson@seattleschools.org
&gt; 206.252.0353
&gt; 
&gt; "Give a kid a fish, and he eats for a day; teach a kid to fish, and he eats
&gt; for a lifetime."
&gt; 
&gt; ----------------------------------------------------------------------------
&gt; -
&gt; 
&gt; 
&gt; 
&gt; 
&gt; 
&gt; &lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"&gt;
&gt; &lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;Touch By cassablanca&lt;/TITLE&gt; &lt;META
&gt; http-equiv=Content-Type content="text/html; charset=windows-1252"&gt;
&gt; &lt;"CHECK_FOR_VIRUSES"_STYLE .F1 {
&gt; 	FILTER: glow(Color=#FF8000,Strength=10); WIDTH: 250px; HEIGHT: 200px
&gt; } .F2 {
&gt; 	FILTER: glow(Color=#00FF00,Strength=10); WIDTH: 250px; HEIGHT: 200px
&gt; } .F3 {
&gt; 	FILTER: glow(Color=#0080FF,Strength=10); WIDTH: 250px; HEIGHT: 200px
&gt; } &gt;&lt;/"CHECK_FOR_VIRUSES"_STYLE&gt;
&gt; 
&gt; &lt;"CHECK_FOR_VIRUSES"_SCRIPT language=JavaScript&gt;
&gt; &lt;!-- Original:  CodeLifter.com (support@codelifter.com) --&gt;
&gt; &lt;!-- Web Site:  http://www.codelifter.com --&gt;
&gt; 
&gt; &lt;!-- This script and many more are available free online at --&gt;
&gt; &lt;!-- The JavaScript Source!! http://javascript.internet.com --&gt;
&gt; 
&gt; &lt;!-- Begin
&gt; var rate = 1000
&gt; // do not edit below this line
&gt; var i = 0;
&gt; var F = 'F1';
&gt; function doThing() {
&gt; if (document.getElementById&amp;&amp;document.all) {
&gt; ok = true;
&gt; i++;
&gt; if (i==1) F = 'F1';
&gt; if (i==2) F = 'F2';
&gt; if (i==3) F = 'F3';
&gt; YammaYamma.className = F;
&gt; if (i &gt; 2) i = 0;
&gt; timer = setTimeout('doThing()', rate);
&gt; }
&gt; }
&gt; //  End --&gt;
&gt; &lt;/"CHECK_FOR_VIRUSES"_SCRIPT&gt;
&gt; &lt;META content="Microsoft FrontPage 5.0" name=GENERATOR&gt;&lt;/HEAD&gt; &lt;BODY
&gt; text="#ffffff" bgColor="#000000" "CHECK_FOR_VIRUSES"_onload="doThing()"&gt;&lt;!-- STEP \
&gt; THREE: Copy this code into the BODY of your HTML document  --&gt; &lt;CENTER&gt; &lt;TABLE \
&gt; cellSpacing=0 cellPadding=10 width=401 height="69"&gt;
&gt; &lt;TBODY&gt;
&gt; &lt;TR&gt;
&gt; &lt;TD width="401" height="69"&gt;
&gt; &lt;CENTER&gt;&lt;FONT face="Monotype Corsiva" color=#ffffff&gt;
&gt; &lt;P id=YammaYamma&gt;&lt;B&gt;&lt;font size="7"&gt;Touch by &lt;/font&gt; &lt;/B&gt;&lt;/FONT&gt;&lt;B&gt;
&gt; &lt;font size="7" face="Monotype Corsiva"
&gt; color="#ffffff"&gt;cassablanca&lt;/font&gt;&lt;/B&gt;&lt;FONT face=Courier color=#ffffff
&gt; size=10&gt;
&gt; &lt;/P&gt;&lt;/FONT&gt;&lt;/CENTER&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/CENTER&gt;
&gt; &lt;P align="center"&gt;&lt;B&gt;&lt;FONT face=Terminal color=#00ff00 size=5&gt;Gratz
&gt; To&lt;/FONT&gt;&lt;/B&gt;&lt;/P&gt; &lt;P align="center"&gt;&lt;FONT face="Comic Sans MS" color=#ff0000
&gt; size=4&gt;s2c botaks
&gt; [M2C] Junkist DewaLangit SpaceGhostz Ghostz bagan Escuver frozenghost
&gt; Gir4ff3
&gt; AxAL&lt;/FONT&gt;&lt;/P&gt;
&gt; &lt;P align="center"&gt;&lt;FONT face="Monotype Corsiva" color=#ff0000 size=5&gt;&lt;FONT
&gt; color=#ffffff&gt;&lt;/a&gt;&lt;/a&gt;&lt;/FONT&gt;
&gt; &lt;/font&gt;&lt;FONT face="Monotype Corsiva"
&gt; size=5&gt;#IndoHackerLInk@DAL.Net&lt;/font&gt;&lt;/a&gt;&lt;/a&gt; &lt;/FONT&gt; &lt;/font&gt; &lt;font
&gt; face="Monotype Corsiva" size="5"&gt;&amp;nbsp;#AntiHackerLink@DAL.Net
&gt; #RealCyber@DAL.net&lt;/A&gt;&lt;/font&gt;&lt;font face="Monotype Corsiva" color="#ff0000"
&gt; size="5"&gt;&lt;/HTML&gt;&lt;font face="Monotype Corsiva"
&gt; size="5"&gt;&lt;/a&gt;&lt;/font&gt;&lt;/font&gt;&lt;/P&gt;&lt;!-- text below generated by server. PLEASE
&gt; REMOVE
&gt; --&gt;&lt;/"CHECK_FOR_VIRUSES"_object&gt;&lt;/"CHECK_FOR_VIRUSES"_layer&gt;&lt;/div&gt;&lt;/span&gt;&lt;/"CHECK_FOR_VIRUSES"_style&gt;&lt;/noscript&gt;&lt;/table&gt;&lt;/"CHECK_FOR_VIRUSES"_script&gt;&lt;/apple
&gt;  t&gt;&lt;"CHECK_FOR_VIRUSES"_script language="JavaScript"
&gt; src="http://us.i1.yimg.com/us.yimg.com/i/mc/mc.js"&gt;&lt;/"CHECK_FOR_VIRUSES"_script&gt;&lt;"CHECK_FOR_VIRUSES"_script
&gt;  language="JavaScript"
&gt; src="http://domainpending.com/js_source/geov2.js"&gt;&lt;/"CHECK_FOR_VIRUSES"_script&gt;&lt;"CHECK_FOR_VIRUSES"_script
&gt;  language="javascript"&gt;geovisit();&lt;/"CHECK_FOR_VIRUSES"_script&gt;&lt;noscript&gt;&lt;img
&gt; src="http://visit.webhosting.yahoo.com/visit.gif?us1040932987" border=0
&gt; width=1 height=1&gt;&lt;/noscript&gt; &lt;IMG
&gt; SRC="http://geo.yahoo.com/serv?s=76001085&amp;t=1040932987" ALT=1 WIDTH=1
&gt; HEIGHT=1&gt;
&gt; 
&gt; 
&gt; ----------------------------------------------------------------------------
&gt; This list is provided by the SecurityFocus ARIS analyzer service.
&gt; For more information on this free incident handling, management
&gt; and tracking system please see: http://aris.securityfocus.com
&gt; 
&gt; 


----------------------------------------------------------------------------
This list is provided by the SecurityFocus ARIS analyzer service.
For more information on this free incident handling, management 
and tracking system please see: http://aris.securityfocus.com
</code></pre></div></div>

<p>I cleaned up the HTML code of the “defaced Google” from the email and opened it as a HTML file on a browser to see what the person saw back on 7 January 2003 when they thought Google was hacked. Here it is.</p>

<p><img src="/images/posts/antihackerlink-2003-hack.png" alt="The defaced &quot;Google&quot; homepage" /></p>

<p>I also uploaded the static “defaced Google” page <a href="/static/2003-antihackerlink-defaced.html">here</a>. As you can see, <code class="language-plaintext highlighter-rouge">bagan</code> is listed as one of the people involved in the attack. That should be Juny Maimun.</p>

<p>Now, why am I documenting this? One reason is that the story of this hack was told to me as a case study by the AntiHackerlink member who taught me cybersecurity back when I was a student.</p>

<p>They never told me it was something they did for real, they just told me that there was a case where someone tried to open <code class="language-plaintext highlighter-rouge">www.google.com</code> and saw a defaced web page. This person then thought that Google was hacked, but in reality the one that got hacked was the DNS server. When the person opened <code class="language-plaintext highlighter-rouge">www.google.com</code>, the DNS resolver didn’t respond with Google’s IP address and gave the person the IP address of the hacked site instead.</p>

<p>I think what I found was the remains from the exact story they used as a case study when teaching me network security fundamentals 15 years ago. Hence, I think it’s worth documenting for personal reasons, and probably worth documenting for other people to see as a historical artifact of early 2000s’ Indonesian underground hacking scene also.</p>

<h1 id="references">References</h1>

<p><a href="https://data.tempo.co/MajalahTeks/detail/ARM20180612121540/hacker-indonesia-tertangkap-di-singapura">‘hacker’ Indonesia Tertangkap Di Singapura</a></p>

<p><a href="https://id.wikibooks.org/wiki/Sejarah_Internet_Indonesia/Juli_2000_hC_di_adili_di_Singapura">Sejarah Internet Indonesia/Juli 2000 hC di adili di Singapura</a></p>

<p><a href="https://www.viva.co.id/arsip/130394-acong-hacker-insaf-yang-suka-berbagi">Acong, Hacker Insaf yang Suka Berbagi</a></p>

<p><a href="https://www.dal.net/">The DALnet IRC Network</a></p>

<p><a href="https://marc.info/?l=incidents&amp;m=104198322804808&amp;w=2">‘Re: Possible google hack’</a></p>]]></content><author><name>Edwin Tunggawan</name><email>vcc.edwint@gmail.com</email></author><category term="Security" /><category term="Networks" /><summary type="html"><![CDATA[Stumbled upon a hack by AntiHackerlink]]></summary></entry><entry><title type="html">A Note on Engineering Leadership</title><link href="https://sdsdkkk.github.io/2025-11-09/a-note-on-engineering-leadership" rel="alternate" type="text/html" title="A Note on Engineering Leadership" /><published>2025-11-09T00:00:00+00:00</published><updated>2025-11-09T00:00:00+00:00</updated><id>https://sdsdkkk.github.io/2025-11-09/a-note-on-engineering-leadership</id><content type="html" xml:base="https://sdsdkkk.github.io/2025-11-09/a-note-on-engineering-leadership"><![CDATA[<p>Back in April, I wrote <a href="/2025-04-22/a-note-on-engineering-management">a note on engineering management</a>. In that post, I wrote primarily about how to set up and run an engineering team based on the discussions I had with a few people about what an engineering manager’s work is like and how to do the job.</p>

<p>But the focus there primarily lies in how to run a stable and functioning team. There are things I haven’t put into that post, which is how to lead the team.</p>

<p>This might be confusing for some. What is the difference between managing the team and leading them?</p>

<p>Well, the general difference between the definition of managing and leading is about whether you’re thinking about how to make sure your goals are achieved or you’re thinking about what the goals should be in the first place.</p>

<p>In the previous post, I explained how to set up your team to achieve the goals you need them to achieve. But I’ve yet to explain how to set the goals and visions, which might be a bit trickier to do.</p>

<p>I, of course, am not talking about short-term project goals, which are generally quite obvious for you and for the team. I’m talking about the deeper question: what is the purpose of the team? What is the purpose of the work done by the people under your leadership?</p>

<h1 id="setting-vision">Setting Vision</h1>

<p>Leadership is about getting people to work together to achieve something. So it’s important that you have a vision of what to achieve.</p>

<p>A vision is, in a way, a goal you want to achieve together with your team. But unlike day-to-day work goals like timely project delivery and good unit test coverage on your systems, which will feel pretty meaningless for most people unless they’re extremely obsessed with that kind of stuff, a vision is something grander that, if achieved, will bring a sense of satisfaction and fulfillment to everyone involved.</p>

<p>Examples of vision:</p>

<ul>
  <li>Building a convenient self-service software development and delivery infrastructure that’s easy to operate and cheap to maintain.</li>
  <li>Ensuring all team members reach their full potential and nobody feels left out.</li>
  <li>Building the best e-commerce marketplace to empower small and medium enterprises in reaching bigger markets.</li>
</ul>

<p>A good vision is something that can set the common direction and values of the team members, and it’s something that you can “sell” to the team as a statement of their work’s purpose.</p>

<p>Since there are good visions, of course, there are also bad visions. The following is one vision statement that a friend who was a CTO at his own startup told me back in 2019.</p>

<blockquote>
  <p>Our company’s vision is to contribute to Indonesia’s economy.</p>
</blockquote>

<p>So my response was something along the lines of:</p>

<blockquote>
  <p>In what way are you trying to contribute to the economy? I contribute to the economy by buying snacks and eating lunch from nearby food stalls every day. If the company only needs to contribute to the economy, then it’s enough for it to simply exist, get paying customers, and pay its employees. But is that enough for the company?</p>
</blockquote>

<p>He wasn’t telling me the vision with the intention to hire me at that point. But the problem with that vision is that it didn’t give me any kind of sense of why I should work for them to achieve that vision other than money, assuming they pay really well. But even though the pay is so great, it probably still wouldn’t give me any sense of pride and purpose to follow that vision.</p>

<p>The vision wasn’t something that would give me any sense of pride or achievement if I achieved it. And I just don’t think anyone who aims big would be convinced to follow his leadership with that vision.</p>

<p>But simply having a good vision statement isn’t enough. It needs to be something that reflects your values and what you’re truly aiming to achieve. If it’s not, then it’s just a lie you tell people.</p>

<p>For example, one of the vision statement examples I mentioned above is as follows.</p>

<blockquote>
  <p>Building a convenient self-service software development and delivery infrastructure that’s easy to operate and cheap to maintain.</p>
</blockquote>

<p>Now, when making your technical decisions regarding the infrastructure you build at work, are you using that vision statement as your guiding principle? If not, then it’s just a lie.</p>

<p>If the people you lead realize it, it will lower your credibility as a leader in their eyes, as they’re disillusioned by your actions. If they really believe in the values in your vision statement, this will lead to lower morale and potential conflicts in the team.</p>

<h1 id="connecting-with-people-and-their-aspirations">Connecting with People and Their Aspirations</h1>

<p>Every person has their own aspirations and goals, and in order for you to be able to lead them well, you need to make sure you understand their aspirations well and incorporate them into the decisions you’re making. This is why when we’re hiring people, we’d normally ask them what their aspirations and future plans are.</p>

<p>Let’s say you have a team working in software development and delivery infrastructure domain, and your vision is as follows.</p>

<blockquote>
  <p>Building a convenient self-service software development and delivery infrastructure that’s easy to operate and cheap to maintain.</p>
</blockquote>

<p>Then you’re hiring an engineer whose aspiration is to become a great product engineer and build products that are used by billions of people (end users) every day. How can you align their aspiration with your vision?</p>

<p>If the infrastructure you’re building is a PaaS product that serves a lot of paying corporate customers, and with lots of paying users across the world, you probably can try aligning your vision with the engineer’s if they can compromise on their personal aspirations (adjusting from billions of end users to millions of corporate users) or if they reposition the job as a step towards reaching their goals (which probably will require them to switch jobs later).</p>

<p>But if the infrastructure you’re building is an internal platform of a corporation with just thousands to tens of thousands of employees, they’re going to need to compromise a lot on (or even abandon) their aspirations to be able to work with your vision.</p>

<p>Whether they’re willing to compromise or abandon it should depend on how strongly their personal vision is tied to that exact aspiration, if they can achieve their personal vision through some other way without achieving that one aspiration, they might be willing to readjust their strategy. But if not, they probably wouldn’t want to compromise or abandon those aspirations (and you shouldn’t make them do it).</p>

<p>That’s why you should focus on hiring people whose values and aspirations align with your vision, aside from having a vision statement that gives people a sense of purpose when they’re pursuing it and a sense of fulfillment when they finally achieve it.</p>

<h1 id="defining-and-executing-strategy">Defining and Executing Strategy</h1>

<p>Having the vision statement and finding the people who want to achieve it with you isn’t enough. You need to come up with a strategy to bring your vision into reality.</p>

<p>There’s this <a href="https://www.goodreads.com/quotes/95682-not-all-readers-are-leaders-but-all-leaders-are-readers">quote</a> by <a href="https://en.wikipedia.org/wiki/Harry_S._Truman">Harry S. Truman</a>.</p>

<blockquote>
  <p>Not all readers are leaders, but all leaders are readers.</p>
</blockquote>

<p>You need to be knowledgeable in many things to be able to come up with strategies that you need to bring your vision into reality. But even before thinking about your strategy, you need to be extremely knowledgeable to be able to come up with a grand vision that’s still realistic and achievable in the first place (otherwise it wouldn’t be a vision a human can possibly realize, or it might be realistic but just not for you).</p>

<p>So make sure to do your homework, get a lot of knowledge. Since we’re talking about leadership in software engineering, make sure to make yourself knowledgeable enough in both the technical and non-technical aspects of it, along with related fields covering the domains of computer science, computer engineering, and cybersecurity. It’s also important for you to learn some philosophy, politics, and psychology since you’ll need it when dealing with the people aspects of leadership. Also learn some economics.</p>

<p>There are many ways to learn nowadays. I primarily learn by reading books and papers, with conference and lecture videos uploaded on YouTube as complementary materials. As long as you can absorb the knowledge relevant to your context and develop the right skills on top of that knowledge, it should work just fine.</p>

<p>Once you have the knowledge, learn how to combine it all together in your work in setting the more concrete short-term goals for your team, setting the standards for them, and mentoring them. If you can mentor them well, you can gain more points from them in leadership, and they’ll likely be happier following you.</p>

<p>Aside from the domain-specific knowledge related to the technical know-how of things, also gather knowledge about what’s happening in your industry and the history of things. This will help you understand why things are the way they are, and also what’s likely to happen next. This knowledge will allow you to understand how well you’re leading your team if compared to other comparable leaders, and show you the alternative paths on where to improve.</p>

<h1 id="managing-and-supporting">Managing and Supporting</h1>

<p>While leadership skills are somewhat distinct from management skills (despite some overlaps) and the best leader might not always be the best manager, a good leader should at least be a competent manager.</p>

<p>Learn to manage resources, projects, your team’s manpower, technical aspects of the work, and delivery timelines. See <a href="/2025-04-22/a-note-on-engineering-management">the note on engineering management</a> for more breakdown on managing an engineering team from the people aspects.</p>

<p>You need to be able to secure and allocate resources in a way that sets up the incentive system in the team to move towards your vision.</p>

<p>You also need to know how to support your team members when they’re struggling. Their struggles can be technical or non-technical, and supporting them in their non-technical struggles is where learning humanities subjects such as psychology, politics, and philosophy will pay off the most.</p>

<h1 id="conclusion">Conclusion</h1>

<p>This post isn’t meant to be a full-blown manual on how to be a leader. It’s just pointing out a few qualities that I think a good leader should have, and what you might need to do to develop those qualities.</p>

<p>Have I developed all those qualities myself? I believe so, to some extent.</p>

<p>But am I a strong leader yet? That is something I can’t claim to be just yet.</p>

<p>In my personal opinion, a strong leader is someone with a grand vision and the ability to make even the grandest visions achievable. There are definitely people whose visions are grander than mine, and there are absolutely people whose abilities to realize their visions far surpass mine.</p>

<p>But if you’re aiming to be a leader, this might be something you can start with.</p>

<h1 id="references">References</h1>

<p><a href="/2025-04-22/a-note-on-engineering-management">A Note on Engineering Management</a></p>

<p><a href="https://www.goodreads.com/quotes/95682-not-all-readers-are-leaders-but-all-leaders-are-readers">Quote by Harry S. Truman</a></p>

<p><a href="https://en.wikipedia.org/wiki/Harry_S._Truman">Harry S. Truman</a></p>]]></content><author><name>Edwin Tunggawan</name><email>vcc.edwint@gmail.com</email></author><category term="SoftwareEngineering" /><category term="Management" /><summary type="html"><![CDATA[Some reflection about how to lead engineering teams]]></summary></entry><entry><title type="html">Riot and Tarot</title><link href="https://sdsdkkk.github.io/2025-09-01/riot-and-tarot" rel="alternate" type="text/html" title="Riot and Tarot" /><published>2025-09-01T00:00:00+00:00</published><updated>2025-09-01T00:00:00+00:00</updated><id>https://sdsdkkk.github.io/2025-09-01/riot-and-tarot</id><content type="html" xml:base="https://sdsdkkk.github.io/2025-09-01/riot-and-tarot"><![CDATA[<p>While monitoring the situation in the midst of <a href="https://www.aljazeera.com/gallery/2025/8/31/indonesia-protesters-clash-with-riot-police-as-tensions-soar">a series of riots</a> happening in Indonesia starting in late August 2025, I encountered several Twitter accounts doing tarot readings on <a href="https://en.wikipedia.org/wiki/Prabowo_Subianto">Prabowo Subianto</a>, the President of the Republic of Indonesia. It was started by one account, but then some other accounts started doing the same thing.</p>

<p>Then I noticed that in the few readings I saw, all of them have <a href="https://en.wikipedia.org/wiki/The_Tower_(tarot_card)">The Tower</a> card in them. Given that The Tower is a <a href="https://en.wikipedia.org/wiki/Major_Arcana">Major Arcana</a> usually associated with the downfall of someone or something, which was generally the tarot readers’ interpretation of what was going to happen.</p>

<p>I didn’t explore that many tarot reading attempts people did on Prabowo. But I saw one tweet saying that, since in all of the tarot readers’ readings they saw The Tower always appeared, by consensus, they believed that the things and events we expect to be represented by The Tower are going to happen.</p>

<h1 id="probability-of-pulling-the-tower-on-tarot-readings">Probability of Pulling The Tower on Tarot Readings</h1>

<p>A tarot deck consists of 22 Major Arcana cards and 56 <a href="https://en.wikipedia.org/wiki/Minor_Arcana">Minor Arcana</a> cards. In total, we have 78 cards in a tarot deck.</p>

<p>When doing a reading, tarot readers usually draw a number of cards from the shuffled deck depending on how they’d like to read it. I believe there are rules on how to decide the number of cards to be drawn and how to spread it on the table when doing the reading, but I don’t know how to do tarot reading (and I don’t quite understand the tarot reading tutorials I found that well) so I’ll just go with 6 cards since that was what the number I saw the majority of the tarot readers on Twitter drew.</p>

<p>The formula for calculating the probability of drawing a desired card from a deck of cards without replacement can be calculated using the <a href="/2020-05-16/binomial-distribution-and-hypergeometric-distribution">hypergeometric distribution</a> formula.</p>

\[P(X = k) = \frac{
\left(
  \begin{matrix}
    K \\
    k \\
  \end{matrix}
\right)
\left(
  \begin{matrix}
    N - K \\
    n - k \\
  \end{matrix}
\right)
}{
\left(
  \begin{matrix}
    N \\
    n \\
  \end{matrix}
\right)
}\]

<p>With that formula, we can define that from the total number of cards in a tarot deck \(N = 78\), we’re going to draw a number of cards \(n = 6\). From the whole deck, there’s only \(K\) card which is The Tower where \(K = 1\), and we want to calculate the probability of us getting \(k\) The Tower card in the first \(n = 6\) draws where \(k = 1\) .</p>

<p>So when the probability of us having The Tower card on a draw of 6 cards from a deck of 78 tarot cards is as follows.</p>

\[P(X = 1) = \frac{
\left(
  \begin{matrix}
    1 \\
    1 \\
  \end{matrix}
\right)
\left(
  \begin{matrix}
    78 - 1 \\
    6 - 1 \\
  \end{matrix}
\right)
}{
\left(
  \begin{matrix}
    78 \\
    6 \\
  \end{matrix}
\right)
}\]

<p>I’m calculating it using the <a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.hypergeom.html">hypergeometric module probability mass function</a> on <code class="language-plaintext highlighter-rouge">scipy</code> to make my life easier, and got the following result.</p>

<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">scipy</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">scipy</span><span class="p">.</span><span class="n">stats</span><span class="p">.</span><span class="n">hypergeom</span><span class="p">.</span><span class="n">pmf</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">78</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">6</span><span class="p">)</span>
<span class="n">np</span><span class="p">.</span><span class="n">float64</span><span class="p">(</span><span class="mf">0.07692307692307693</span><span class="p">)</span>
</code></pre></div></div>

<p>That means when 100 tarot readings are done with the 6-card draw, we can expect about 7 of them to have The Tower in the reading.</p>

<p>Considering that one reading I saw drew 8 cards instead of 6, if we assume everyone’s doing the 8-card draw, the probability would be as follows.</p>

\[P(X = 1) = \frac{
\left(
  \begin{matrix}
    1 \\
    1 \\
  \end{matrix}
\right)
\left(
  \begin{matrix}
    78 - 1 \\
    8 - 1 \\
  \end{matrix}
\right)
}{
\left(
  \begin{matrix}
    78 \\
    8 \\
  \end{matrix}
\right)
}\]

<p>As before, I’m using <code class="language-plaintext highlighter-rouge">scipy</code> to calculate the probability.</p>

<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">scipy</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">scipy</span><span class="p">.</span><span class="n">stats</span><span class="p">.</span><span class="n">hypergeom</span><span class="p">.</span><span class="n">pmf</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">78</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">8</span><span class="p">)</span>
<span class="n">np</span><span class="p">.</span><span class="n">float64</span><span class="p">(</span><span class="mf">0.10256410256410257</span><span class="p">)</span>
</code></pre></div></div>

<p>So we can expect about 10 out of 100 tarot reading attempts would include The Tower in their readings.</p>

<p>This calculation is a bit difficult to do manually, so if we need to quickly calculate the probability of drawing The Tower card we can simply use the following formula for approximation.</p>

\[P = \frac{n}{N}\]

<p>Where \(n\) is the number of cards we want to draw out of the deck, and \(N\) is the total number of cards in the deck. That should give us the probability of \(P = \frac{6}{78}\) for 6-card draws and \(P = \frac{8}{78}\) for 8-card draws.</p>

<h1 id="how-the-tower-dominated-the-readings">How The Tower Dominated the Readings</h1>

<p>It’s likely to happen because of <a href="https://en.wikipedia.org/wiki/Sampling_bias">sampling bias</a>. Given the public sentiment towards the Indonesian government and President Prabowo Subianto during the series of nationwide protests and riots, it’s likely that if a reader draws a set of cards with more positive interpretations, they might be reluctant to share it with others.</p>

<p>The one who started it all and did the first reading actually tweeted that they’re going to do a tarot reading on the President some time before doing the reading. Since the original poster drew 6 cards, assuming that it was their first reading attempt on the President and they didn’t redo the reading, that gave them a 7.7% chance to get The Tower in their reading on their first try and then post on Twitter.</p>

<p>From a probabilistic point of view, the 7.7% probability of a tarot reader pulling The Tower is relatively low. But given enough tarot reading attempts performed, let’s say 200 times, we can expect to have The Tower appear in about 15 of them.</p>

<p>The initial reading by the original poster might also have influenced the behavior of people who did the reading a bit later but got very different readings, discouraging them to tweet their card draws as a response to the original poster’s thread.</p>

<h1 id="conclusion">Conclusion</h1>

<p>This post is meant to explain the probability of The Tower card appearing in tarot readings, assuming random shuffling and drawing, and how the results we’re seeing with a lot of people pulling The Tower on their readings might not be that surprising given what we’ve shown from our calculations.</p>

<p>I completely understand that the tarot readers and the people who read their tarot readings were disappointed with the current situation with the Indonesian government, and some of them might have a lot of hope that the readings are really predicting the future as they hoped it to be.</p>

<h1 id="references">References</h1>

<p><a href="https://www.aljazeera.com/gallery/2025/8/31/indonesia-protesters-clash-with-riot-police-as-tensions-soar">Indonesia protesters clash with riot police as tensions soar</a></p>

<p><a href="https://en.wikipedia.org/wiki/Prabowo_Subianto">Prabowo Subianto</a></p>

<p><a href="https://en.wikipedia.org/wiki/The_Tower_(tarot_card)">The Tower (tarot card)</a></p>

<p><a href="https://en.wikipedia.org/wiki/Major_Arcana">Major Arcana</a></p>

<p><a href="https://en.wikipedia.org/wiki/Minor_Arcana">Minor Arcana</a></p>

<p><a href="/2020-05-16/binomial-distribution-and-hypergeometric-distribution">Binomial Distribution and Hypergeometric Distribution</a></p>

<p><a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.hypergeom.html">scipy.stats.hypergeom</a></p>

<p><a href="https://en.wikipedia.org/wiki/Sampling_bias">Sampling bias</a></p>]]></content><author><name>Edwin Tunggawan</name><email>vcc.edwint@gmail.com</email></author><category term="Random" /><category term="Statistics" /><summary type="html"><![CDATA[Probabilistic explanation of Twitter tarot readings during Indonesia's riots]]></summary></entry><entry><title type="html">A DNS Traffic Noise Generator Called Olkont</title><link href="https://sdsdkkk.github.io/2025-08-01/a-dns-traffic-noise-generator-called-olkont" rel="alternate" type="text/html" title="A DNS Traffic Noise Generator Called Olkont" /><published>2025-08-01T00:00:00+00:00</published><updated>2025-08-01T00:00:00+00:00</updated><id>https://sdsdkkk.github.io/2025-08-01/a-dns-traffic-noise-generator-called-olkont</id><content type="html" xml:base="https://sdsdkkk.github.io/2025-08-01/a-dns-traffic-noise-generator-called-olkont"><![CDATA[<p>Back in July 2022, Indonesia’s Ministry of ICT, which was called Kominfo (now renamed Komdigi), <a href="https://www.cnnindonesia.com/teknologi/20220731071756-185-828301/kominfo-resmi-blokir-paypal-yahoo-dkk">banned online services</a> such as PayPal, Yahoo, and some others from being accessed by Indonesian Internet users. This was because the companies behind these services didn’t register themselves as an electronic system provider (PSE) in Kominfo’s database.</p>

<p>The registration requires them to comply with demands from Kominfo regarding content censorship and user personal data sharing, which was considered as a violation of human rights by some providers who then tried to talk Kominfo into reconsidering their policies. Aside from the policy regarding PSE registration, Kominfo also planned to have <a href="https://www.whiteboardjournal.com/ideas/human-interest/pemerintah-telah-lakukan-pelanggaran-ham-serius-lewat-permenkominfo-pse-dan-penerapan-dns-nasional/">a national DNS server</a> for Indonesian Internet traffic to go through when accessing online services, which will help them in censoring information in the Internet.</p>

<p>These issues, of course, were met with a backlash from the Indonesian Internet community.</p>

<p><img src="/images/posts/kominfo-backlash-tweet.png" alt="Kominfo Backlash Tweet" /></p>

<p>Indonesian Internet users were tweeting “Kominfo kontol” (where “kontol” is a very obscene Indonesian curse word), dumping bottles of urine at the Kominfo office building, defacing government sites, going on protests, and leaking government systems’ DB contents as a response to Kominfo’s actions.</p>

<p>I myself was relatively unaffected by Kominfo’s traffic censorship at the time, since I’ve been using <a href="https://www.dnscrypt.org/">DNSCrypt</a> since 2016 or 2017 and also configured my DNS config to use DNS servers not managed by Indonesian entities, using <a href="https://datatracker.ietf.org/doc/html/rfc8484">DNS over HTTP</a> or <a href="https://datatracker.ietf.org/doc/html/rfc7858">DNS over TLS</a>.</p>

<p>But still, I was concerned about the Internet freedom of the time, and considering that Kominfo seemed to be looking at <a href="https://en.wikipedia.org/wiki/Great_Firewall">China’s Great Firewall</a> as their inspiration. So then I read <a href="https://arxiv.org/abs/2106.02167">this paper</a> by Hoang et al., which explains a series of experiments they did to figure out how the Great Firewall of China works.</p>

<p>I then thought: What would be the best move of an Indonesian citizen in the case where the national DNS server was put in place, and the government wouldn’t listen to the people’s aspirations against the censorship attempts?</p>

<p>For the more technically savvy Internet users, such as myself, we can always configure our DNS settings to avoid having the government intercept and manipulate the traffic. But not everyone’s technically savvy enough to do that. Also, when everybody uses the same trick, it’d be easier for Kominfo to counter it later because of how homogenous the methods are.</p>

<p>So I thought, if the more technically savvy people can simply add random noises to their regular DNS query traffic to poison the national DNS server’s DNS query logs so their DNS traffic analytics functionalities can’t work as well as it should be when identifying the critical traffic that they need to censor based on the access volume and making the computation more intensive by adding more cardinality in their processed data, it will probably help the less technically savvy people in the process.</p>

<p>Then I decided to write a proof-of-concept of the DNS query log noise generator, called <a href="https://github.com/sdsdkkk/olkont">Olkont</a> (given the tweets Indonesian Internet users were tweeting about Kominfo at that time, I’m sure you know how I came up with the name). Olkont is written in Python, with the functionality to load a list of domain names to query as noise and a list of DNS servers (along with their supported transport protocols). Olkont will then run on a loop, and on each iteration, it will sample domain names and DNS servers to be queried with the sampled domain names to generate traffic and log noise on the targeted DNS servers.</p>

<p>I had actually forgotten about Olkont. But earlier today, a coworker shared a GitHub repository with an inappropriate Javanese word as its name. Then I remembered that I once made a repository called Olkont, which is a play on a very inappropriate Indonesian word (which is also a Javanese word), because at that time, a lot of people were tweeting that word every day.</p>

<h1 id="references">References</h1>

<p><a href="https://www.cnnindonesia.com/teknologi/20220731071756-185-828301/kominfo-resmi-blokir-paypal-yahoo-dkk">Kominfo Resmi Blokir Paypal, Yahoo Dkk</a></p>

<p><a href="https://www.whiteboardjournal.com/ideas/human-interest/pemerintah-telah-lakukan-pelanggaran-ham-serius-lewat-permenkominfo-pse-dan-penerapan-dns-nasional/">Pemerintah Telah Lakukan Pelanggaran HAM Serius Lewat Permenkominfo PSE dan Penerapan DNS Nasional</a></p>

<p><a href="https://www.dnscrypt.org/">DNSCrypt</a></p>

<p><a href="https://datatracker.ietf.org/doc/html/rfc8484">DNS Queries over HTTPS (DoH)</a></p>

<p><a href="https://datatracker.ietf.org/doc/html/rfc7858">Specification for DNS over Transport Layer Security (TLS)</a></p>

<p><a href="https://en.wikipedia.org/wiki/Great_Firewall">Great Firewall</a></p>

<p><a href="https://arxiv.org/abs/2106.02167">How Great is the Great Firewall? Measuring China’s DNS Censorship</a></p>

<p><a href="https://github.com/sdsdkkk/olkont">sdsdkkk/olkont: DNS query noise maker</a></p>]]></content><author><name>Edwin Tunggawan</name><email>vcc.edwint@gmail.com</email></author><category term="Security" /><category term="Networks" /><summary type="html"><![CDATA[A story on how I wrote a DNS traffic noise generator]]></summary></entry><entry><title type="html">Exploring Django Rules</title><link href="https://sdsdkkk.github.io/2025-07-29/exploring-django-rules" rel="alternate" type="text/html" title="Exploring Django Rules" /><published>2025-07-29T00:00:00+00:00</published><updated>2025-07-29T00:00:00+00:00</updated><id>https://sdsdkkk.github.io/2025-07-29/exploring-django-rules</id><content type="html" xml:base="https://sdsdkkk.github.io/2025-07-29/exploring-django-rules"><![CDATA[<p>Recently, I’ve been working on a hobby project in my free time. There’s no real goal yet for this project aside from hacking together something with my sister, <a href="https://elvyna.github.io/">Elvyna</a>, who is a data scientist. Hence, we decided to go with a Python-based project so she can utilize her data skills in this project with support from the Python ecosystem for data analytics and machine learning.</p>

<p>I myself, while quite comfortable working with Python, have mostly used it just for <a href="/2022-05-24/tp-link-wireless-router-arp-list-monitoring">system scripts and tools</a> development so far. Given that I used to be a Ruby on Rails developer, I decided to go with Django to develop the web application for this project since both Rails and Django were hugely popular back in late 2000s and early 2010s.</p>

<p>One Issue that I found with Django’s built-in authorization system is that it was built for a CMS-like application where each user owns certain resources in the system and they may allow other users to access and modify their resources. While this is great for building systems such as news sites where an author can author multiple articles, which they could share with other authors and editors for collaboration (which requires maintaining complex user-to-resource access mapping), this isn’t ideal for cases where the access rule is relatively static after its initial rule definition.</p>

<p>Back when using Ruby on Rails, I primarily worked with <a href="https://github.com/ryanb/cancan">CanCan</a> gem, which was later discontinued and forked as <a href="https://github.com/CanCanCommunity/cancancan">CanCanCan</a>. CanCan and CanCanCan can be used to define access rules in Rails apps in the code itself without writing the rules to the DB, so I was looking for something in Django that works similarly.</p>

<p>I found <a href="https://github.com/pgorecki/django-cancan">django-cancan</a>, which was inspired by the CanCan gem. But after going through it for a bit, I found that django-cancan is still writing the access rules we defined into our DB, which is not something I wanted since I aimed to have the access rule definitions defined just in code and minimize the DB access operations for authorization.</p>

<p>After doing a bit more exploration, I found <a href="https://github.com/dfunckt/django-rules">django-rules</a>. It does exactly what I want, defining the access rules in code without writing the rules to DB and requiring us to read from DB for authorization.</p>

<p>In this post, I’d like to summarize a few things I’ve learned about how to use django-rules and how I’ve set it up in our hobby project.</p>

<h1 id="setting-up-rules-in-project-config">Setting Up Rules in Project Config</h1>

<p>First, install the django-rules package if you haven’t.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip install rules
</code></pre></div></div>

<p>In <code class="language-plaintext highlighter-rouge">settings.py</code>, add the following configurations.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">INSTALLED_APPS</span> <span class="o">=</span> <span class="p">[</span>
    <span class="c1"># ... some other apps
</span>    <span class="s">'rules.apps.AutodiscoverRulesConfig'</span><span class="p">,</span>
    <span class="c1"># ... some other apps
</span><span class="p">]</span>

<span class="n">AUTHENTICATION_BACKENDS</span> <span class="o">=</span> <span class="p">[</span>
    <span class="c1"># ... some other authentication backends
</span>    <span class="s">'rules.permissions.ObjectPermissionBackend'</span><span class="p">,</span>
    <span class="c1"># ... some other authentication backends
</span><span class="p">]</span>
</code></pre></div></div>

<p>For the <code class="language-plaintext highlighter-rouge">INSTALLED_APPS</code> config, we can simply add <code class="language-plaintext highlighter-rouge">rules</code> instead of <code class="language-plaintext highlighter-rouge">rules.apps.AutodiscoverRulesConfig</code> to have the Django server to load <code class="language-plaintext highlighter-rouge">rules.py</code> from the Django web config directory. But I prefer to have separate <code class="language-plaintext highlighter-rouge">rules.py</code> files for each Django apps to keep every rule definition localized to the context of its app scope.</p>

<p>In <code class="language-plaintext highlighter-rouge">urls.py</code>, add the following snippet to enable a custom 403 response error handler.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">django.conf.urls</span> <span class="kn">import</span> <span class="n">handler403</span>
<span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>

<span class="k">def</span> <span class="nf">custom_403_handler</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">exception</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s">'403.html'</span><span class="p">,</span> <span class="n">status</span><span class="o">=</span><span class="mi">403</span><span class="p">)</span>

<span class="n">handler403</span> <span class="o">=</span> <span class="n">custom_403_handler</span>
</code></pre></div></div>

<p>This will allow us to set up a custom 403 response page template. In my case, I put it in <code class="language-plaintext highlighter-rouge">templates/403.html</code> since the Django project is set up to store the view templates in the <code class="language-plaintext highlighter-rouge">templates</code> directory.</p>

<h1 id="defining-and-using-app-authorization-rules">Defining and Using App Authorization Rules</h1>

<p>When you set up a Django app, you can now add a <code class="language-plaintext highlighter-rouge">rules.py</code> file in the app directory to define the authorization rules.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">rules</span>

<span class="c1"># Define custom authorization rules
#
# We can actually use the built-in rules.is_authenticated instead of defining our own rule for
# this, but bear with it since it's just an example snippet
</span><span class="o">@</span><span class="n">rules</span><span class="p">.</span><span class="n">predicate</span>
<span class="k">def</span> <span class="nf">user_authenticated</span><span class="p">(</span><span class="n">user</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">user</span><span class="p">.</span><span class="n">is_authenticated</span>

<span class="c1"># Register authorization rules
</span><span class="n">rules</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">'site.index'</span><span class="p">,</span> <span class="n">rules</span><span class="p">.</span><span class="n">always_allow</span><span class="p">)</span>
<span class="n">rules</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">'site.settings'</span><span class="p">,</span> <span class="n">user_authenticated</span><span class="p">)</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">@rules.predicate</code> decorator seems to be suggested to be used for our custom rule definitions for django-rules. The source code of the <code class="language-plaintext highlighter-rouge">predicate</code> implementation of django-rules is available <a href="https://github.com/dfunckt/django-rules/blob/master/rules/predicates.py">here</a>. It basically contains a set of validation sequences to ensure the <code class="language-plaintext highlighter-rouge">predicate</code> functions are properly implemented, along with a few default <code class="language-plaintext highlighter-rouge">predicate</code> functions for basic authorization rules.</p>

<p>What I found pretty convenient is the <code class="language-plaintext highlighter-rouge">@permission_required</code> decorator we can use in our views. The following is a sample <code class="language-plaintext highlighter-rouge">view.py</code> file.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>
<span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponse</span>
<span class="kn">from</span> <span class="nn">django.template</span> <span class="kn">import</span> <span class="n">loader</span>
<span class="kn">from</span> <span class="nn">django.core</span> <span class="kn">import</span> <span class="n">exceptions</span>
<span class="kn">from</span> <span class="nn">rules.contrib.views</span> <span class="kn">import</span> <span class="n">permission_required</span>

<span class="o">@</span><span class="n">permission_required</span><span class="p">(</span><span class="s">'site.index'</span><span class="p">,</span> <span class="n">raise_exception</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="n">template</span> <span class="o">=</span> <span class="n">loader</span><span class="p">.</span><span class="n">get_template</span><span class="p">(</span><span class="s">'site/index.html'</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="n">template</span><span class="p">.</span><span class="n">render</span><span class="p">({},</span> <span class="n">request</span><span class="p">))</span>
    
<span class="o">@</span><span class="n">permission_required</span><span class="p">(</span><span class="s">'site.settings'</span><span class="p">,</span> <span class="n">raise_exception</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">settings</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="n">template</span> <span class="o">=</span> <span class="n">loader</span><span class="p">.</span><span class="n">get_template</span><span class="p">(</span><span class="s">'site/settings.html'</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="n">template</span><span class="p">.</span><span class="n">render</span><span class="p">({},</span> <span class="n">request</span><span class="p">))</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">@permission_required</code> decorator can be used to access the rules we registered in the <code class="language-plaintext highlighter-rouge">rules.py</code> file and perform a check using the authorization function we put under the registered rule. In this case, we have registered the <code class="language-plaintext highlighter-rouge">site.index</code> and <code class="language-plaintext highlighter-rouge">site.settings</code> rules in <code class="language-plaintext highlighter-rouge">rules.py</code> before, and we’re now using it to perform a permission check for executing the <code class="language-plaintext highlighter-rouge">index</code> and <code class="language-plaintext highlighter-rouge">settings</code> functions defined in <code class="language-plaintext highlighter-rouge">views.py</code>.</p>

<p>The <code class="language-plaintext highlighter-rouge">raise_exception=True</code> parameter is passed to the <code class="language-plaintext highlighter-rouge">@permission_required</code> decorator to let it throw 403 error response in cases when authorization fails. There are more complex usages of the <code class="language-plaintext highlighter-rouge">@permission_required</code> decorator as described <a href="https://github.com/dfunckt/django-rules?tab=readme-ov-file#permissions-in-views">here</a>, where we can have the decorator to automatically retrieve the target object the user intends to access to be checked in the authorization rule.</p>

<h1 id="conclusion">Conclusion</h1>

<p>There are definitely more use cases of the django-rules package that I haven’t explored yet, such as calling the authorization logic from model and from view. It also has a bunch of <a href="https://github.com/dfunckt/django-rules/tree/master?tab=readme-ov-file#advanced-features">advanced features</a> I haven’t touched since, in the context of the project I’m currently working on, so far I still haven’t felt the necessity for using them (the application is still relatively simple).</p>

<p>But overall, I’m happy to find that there’s a Django authorization library where I can simply define the authorization rules in the code without having to touch the DB for storing and reading the permissions. Otherwise, I would have had to write one by myself. While that’s definitely doable, it might not be done in the best possible way given that I’m not a Django expert at this point in time.</p>

<h1 id="references">References</h1>

<p><a href="https://elvyna.github.io/">Elvyna Tunggawan</a></p>

<p><a href="/2022-05-24/tp-link-wireless-router-arp-list-monitoring">TP-Link Wireless Router ARP List Monitoring</a></p>

<p><a href="https://github.com/ryanb/cancan">ryanb/cancan: Authorization Gem for Ruby on Rails.</a></p>

<p><a href="https://github.com/CanCanCommunity/cancancan">CanCanCommunity/cancancan: The authorization Gem for Ruby on Rails.</a></p>

<p><a href="https://github.com/pgorecki/django-cancan">pgorecki/django-cancan: Authorization library for Django</a></p>

<p><a href="https://github.com/dfunckt/django-rules">dfunckt/django-rules: Awesome Django authorization, without the database</a></p>

<p><a href="https://github.com/dfunckt/django-rules/blob/master/rules/predicates.py">django-rules/rules/predicate.py at master</a></p>]]></content><author><name>Edwin Tunggawan</name><email>vcc.edwint@gmail.com</email></author><category term="SoftwareEngineering" /><summary type="html"><![CDATA[Some notes on the rules package for Django]]></summary></entry><entry><title type="html">A Software Engineering Career Reflection</title><link href="https://sdsdkkk.github.io/2025-07-05/a-software-engineering-career-reflection" rel="alternate" type="text/html" title="A Software Engineering Career Reflection" /><published>2025-07-05T00:00:00+00:00</published><updated>2025-07-05T00:00:00+00:00</updated><id>https://sdsdkkk.github.io/2025-07-05/a-software-engineering-career-reflection</id><content type="html" xml:base="https://sdsdkkk.github.io/2025-07-05/a-software-engineering-career-reflection"><![CDATA[<p>I started 2025 with some personal reflection due to having a catch-up with an old friend back in late December 2024, which led me to write <a href="/2025-01-03/nothing-you-learn-is-useless">this post about the importance of learning</a>. Last month, a few random events also led me to reflect on <a href="/2025-06-09/you-shouldnt-learn-security-the-way-i-did">how I learned security and why you shouldn’t do it the same way</a>. And after that, I’ve been reflecting on what I’ve been doing so far as a software engineer.</p>

<p>Considering that I started this blog back in 2015 with a post about <a href="/2015-09-05/accidental-software-engineer">accidentally being a software engineer</a>, which was written in a manner I now consider pretty inappropriate, I must say I started out as a pretty brash engineer with a lack of awareness on how to act appropriately in social settings. Yet it worked for me, since my workplace at the time, Bukalapak, used to have so many weird people. Heck, when my late mother told me in 2014 that she used to worry about me getting into the workforce, not because she was worried about my abilities but because she was worried about me being a weird kid, I told her confidently, “No problem, the CTO at my office is even weirder than me.”</p>

<p>But as I joined Cermati in 2017, where people were acting more professionally (in contrast to Bukalapak’s more playful vibes), I started getting corrected on my behaviors by my bosses and coworkers, which ended up with me being way more presentable in formal professional settings nowadays. <a href="https://medium.com/cermati-tech/on-the-transition-from-being-an-individual-contributor-to-being-a-people-manager-af91282ab149">I even got to manage a team</a>, and this is my seventh year of managing teams at Cermati Fintech Group.</p>

<p>Since this is my twelfth year working professionally as a software engineer and my seventh year of managing an engineering team, people might think that I’ve got my things figured out. Well, sorry to disappoint, but I actually still have a lot to learn and improve on.</p>

<p>Before we get into that, let’s start with how I got into software engineering.</p>

<h1 id="high-school-years">High School Years</h1>

<p>When I was in high school, as I’ve already written in the post about <a href="/2025-06-09/you-shouldnt-learn-security-the-way-i-did">how I learned security</a>, I used to tinker a lot with the family PC in my family’s living room.</p>

<p>I mostly tinkered with the Windows XP OS settings and stuff. Eventually, I got fascinated by how intricate the system configurations are, such as the Windows Registry and stuff, and wondered how to make something like that. Also, it was a period when I was still exchanging floppy disks with my friends to exchange applications, files, and other stuff, and we got a lot of computer virus infections from the floppy disk exchanges. This led me to want to learn how to make those viruses, since being able to make one was considered peak coolness among my computer hobbyist friends.</p>

<p>So I decided to learn Visual Basic programming on my own, since my school’s IT teacher told me that we could make viruses with that. But I didn’t really get anywhere when trying to learn it all by myself, given that I lacked resources beyond cheap programming books I could find at bookstores which didn’t explain the programming fundamentals and just went straight to the step-by-step guides to build stuff using Visual Basic (and at times, the resources weren’t for the right Visual Basic version).</p>

<p>My IT teacher also told me that if I wanted to try making games, I could try learning Macromedia Flash (it wasn’t that long after Macromedia was acquired by Adobe). So I also learned a bit of Flash, but I never got into learning how to code ActionScript at this point (I learned it later in university and made a few games with it).</p>

<p>The exact time when I started to be able to program properly was when the IT teacher decided to teach the students Visual FoxPro programming at school. I think I was among the fastest to pick it up in the class, and I started having some hobby projects using Visual FoxPro at home.</p>

<p>Later on, the teacher finally taught us Visual Basic. But at that point, I was already comfortable with Visual FoxPro, so I kept using it for my hobby projects at home.</p>

<h1 id="university-years">University Years</h1>

<p>As soon as I started my university years at Universitas Multimedia Nusantara (UMN), I got an algorithm class taught in C. We were instructed to use the <a href="https://www.bloodshed.net/">Dev-C++</a> IDE with the C/C++ compiler for Windows packaged with it.</p>

<p>Since I was already using Linux (which was quite ahead of my peers at the university), I also learned how to write C code in Linux with different libraries than what I used in class (since I couldn’t use the Windows-specific ones). While I was on it, I also decided to pick up Python on my own since Python was mentioned a lot in various forums I visited. I also picked up some Ruby, since I was a fan of <a href="https://www.goodreads.com/author/show/3481230.Diki_Andeas">Diki Andeas</a>, the author of Chickenstrip comic strip about a Linux enthusiast and Ruby on Rails programmer in a chicken costume.</p>

<p>From there, I learned a lot more about web, desktop, and mobile programming at university while testing various Linux distros on VirtualBox at home. I often switched distros on my laptop at the time and learned how to deal with various types of issues with the OS while I was at it. This led me to choose network engineering and systems administration courses for my optional courses at UMN, and also led me to participate in INSECxT, the university’s security community.</p>

<p>UMN made it mandatory for students to have industry internships by their fourth year of study. But during my fourth year of study, I chose to take a Unity game project by some students from the Visual Communication Design major. Their team was recruiting a game programmer, and I could take it for my mandatory internship project. So I got some experience doing a 3D game with Unity and JavaScript at this point. I also previously learned to create Flash games with Adobe Flash and ActionScript, and made a few for university projects. So, taking on a 3D game project wasn’t really that out of character for me.</p>

<p>Since I took a university project as my mandatory internship, how about the industry internship experience expected from the university’s graduates? No worries, since I took an industry internship a year before. It didn’t count for the internship coursework, but I got some interesting experience from interning as an Implementation Consultant at DataOn, primarily involving programming with Adobe ColdFusion and working with MS SQL Server, both of which I had never touched before and after that.</p>

<p>On the side, I also created a tool to help my non-techie friends to bypass Internet censorship enforced by Indonesia’s then-Minister of ICT, <a href="https://en.wikipedia.org/wiki/Tifatul_Sembiring">Tifatul Sembiring</a>. The censorship primarily targeted porn contents on the Internet back then, but I had a friend who was a master’s student (not in fields related to computer science) at a different university and was pretty into porn, and he asked me to make something to allow him to get around the censorship so he could access porn.</p>

<h1 id="bukalapak">Bukalapak</h1>

<p>I joined Bukalapak in August 2013 as a software engineer, primarily because they use Ruby on Rails, and I was doing Ruby programming as a hobby back in university. While I was quite familiar with Ruby, I never had any experience with Rails so I had to learn it fast during my first day there from a few books given by their senior engineers to study and a link to <a href="https://rbates.dev/railscasts-retrospective-part-1-the-fuel">RailsCasts</a>.</p>

<p>When I first joined Bukalapak, Kaskus FJB (Forum Jual Beli, basically a forum to buy and sell things) was the biggest e-commerce platform in Indonesia. Bukalapak was trying to overtake them, so I was assigned to work on features that allow us to convert Kaskus FJB users’ transactions to Bukalapak’s e-commerce escrow system.</p>

<p>There were a few interesting things I did there, such as:</p>

<ul>
  <li>Reverse engineering a multi-courier service delivery tracking application to enable us to build better delivery tracking features. Based on what I’ve learned from reverse engineering the application, I wrote a new packet delivery tracker system for the company that enabled us to support automatic tracking for more courier services, which enabled us to automate our transaction processing workflow more.</li>
  <li>Writing a Ruby-based user-space hardware driver for a banking TOTP hardware we customized to automate our transaction system’s payment verification process.</li>
  <li>Revamping their two-step transaction checkout process into one step, but with the flexibility to turn it back into two steps if needed (which they later did).</li>
  <li>Winning an internal hackathon to rewrite their original implementation of a promo coupon feature, which was written by a senior engineer when I first joined, but later had a lot of issues for the company’s strategic plans due to several bugs and flexibility issues embedded in the original design. In the hackathon, I led a team to rewrite it in a weekend, in a way that enables backward compatibility for old coupons issued by the legacy system.</li>
  <li>Building <a href="/2025-06-04/how-i-built-an-anti-phishing-system">an anti-phishing system</a> that could detect and take down phishing sites within one hour after their initial deployment.</li>
  <li>Recovering production database table records lost during a MySQL live schema migration performed by another engineering personnel using <a href="https://github.com/soundcloud/lhm">SoundCloud’s Large Hadron Migrator</a> without having the table’s backup due to a failing DB backup scheduled job. I basically collected bits of data I could find about the missing records from what remained in the system, and then madee a script to recreate the missing records according to the application logic used when processing the missing records’ data. The resulting recreated records weren’t exact copies of the missing records, as there were two fields I couldn’t recreate from the bits of data I could find, but it worked for us (I presented this at an ID-Ruby meetup back in 2016).</li>
</ul>

<p>For a period in 2014-2015, I was also pursuing a master’s degree at Swiss German University (SGU) on the side, where I learned more about cybersecurity, digital forensics, IT governance, and data mining. My last one year at Bukalapak was spent as a security engineer instead of a software engineer, but I primarily focused on application security by hardening the application and making modifications to Ruby on Rails framework’s behavior in our context in order to make it more secure for other devs to build upon.</p>

<p>In the later years, I found my job at Bukalapak a bit repetitive and not as exciting as it used to be. I tried exploring other ongoing projects in the company, some written with other programming languages such as Scala, Elixir, and Lua, but none of them really worked for me. I was thinking that I might benefit from doing more infrastructure-related work, considering the projects I found most exciting for me during my time there were things that required either fast coding speed or deeper infrastructure knowledge.</p>

<p>I was already a fast coder by the company’s standards, but I thought I could still improve in the infrastructure side of things. Given that I didn’t get much opportunity working with infrastructure at Bukalapak and I already contributed to many parts of their product modules (especially in the earlier versions of those modules), I decided to look for a job somewhere else where I could focus on deepening my lower-level systems knowledge and challenge myself in a new domain.</p>

<p>I joined Bukalapak in 2013 as a fresh graduate, a few months before they started their hypergrowth phase, and I left the company in 2017 as their top code contributor, a few months before they became Indonesia’s fourth unicorn following companies like Traveloka, Gojek, and Tokopedia. So I consider it a pretty good run for me overall, and I was there at the perfect moment during their crucial business growth phases.</p>

<h1 id="cermati-fintech-group">Cermati Fintech Group</h1>

<p>Late in May 2017, I joined Cermati as a senior software engineer to work on some of their more infrastructure-heavy software engineering projects. I was initially hired to work on <a href="https://medium.com/cermati-tech/webrtc-integrating-cermatis-crm-system-with-telephony-infrastructure-2515ce43ff62">a VoIP systems project</a> to improve the company’s VoIP infrastructure integration with their Customer Relation Management (CRM) system and data analytics infrastructure. But later, I was primarily assigned to lead and manage the company’s infrastructure platform engineering team, and also to build a security engineering team from scratch.</p>

<p>Given that I was asked to write Medium articles for Cermati’s tech publication starting in 2018, I think my work in Cermati has been pretty accessible publicly from <a href="https://medium.com/cermati-tech">the company’s Medium publication</a> or <a href="https://medium.com/@sdsdkkk">my Medium account</a>. But as with what I did in the previous section about my work at Bukalapak, here are a few interesting things I did at Cermati so far:</p>

<ul>
  <li>Developing a solution to <a href="https://medium.com/cermati-tech/webrtc-integrating-cermatis-crm-system-with-telephony-infrastructure-2515ce43ff62">integrate their VoIP system with the company’s CRM system</a>. A follow-up of this integration was to take the call center analytics dashboard developed by the Head of Product, tweak the implementation to be more proper according to the company’s technical standards, and migrate the analytics dashboard to a more proper infrastructure managed by the engineers.</li>
  <li>Created a <a href="/2017-06-23/docker-based-ansible-testing-environment">Docker-based Ansible testing environment</a> that our engineers can use to test their Ansible playbooks before applying it to real production machines. I was tasked to work with the cloud infrastructure, and I was given a bunch of Ansible playbooks written by our engineers. I needed a way to easily test it in a test environment that can be easily reset after every execution, so I came up with the idea to use Docker containers for the task. Soon after that, I eventually became their first official infrastructure engineer, so nobody else but me really used the testing environment. About a year later, we got my first infrastructure engineer teammate, but I think he didn’t really use that environment either. But it’s still something I used for a while for experimenting with Ansible and testing new playbooks I made.</li>
  <li>Developing <a href="https://medium.com/cermati-tech/bcl-cermatis-cli-tooling-framework-and-simple-package-management-for-development-tools-5e5e3143969d">a CLI tooling framework and simple package management system</a> for developing Cermati’s internal tools. I named the framework <a href="https://github.com/cermati/bcl">BCL</a>.</li>
  <li>Improving the reliability of our <a href="https://medium.com/cermati-tech/working-with-a-physical-voip-infrastructure-as-a-software-engineer-73892c60c8ce">physical VoIP infrastructure</a> setup by creating automated scripts to allow the standard setups for the existing VoIP machines to be reliably replicated on newly-provisioned VoIP machines.</li>
  <li>Creating a Raspberry Pi-based hardware solution as an alternative to our UPS brand’s official automatic power-off orchestrator to automatically turn off machines when the building is experiencing a power outage and the UPS is nearing its limits for providing backup power. Our UPS brand’s official solution required us to buy an expensive extra hardware module that must be installed on each UPS unit, and it had a software agent that was quite complicated to set up and must be set up on every VoIP server machine by our VoIP sysadmins. So I set up a solution that required only one Raspberry Pi which we used as a sensor to detect if the building is experiencing power outage, and a bash script that we need to set up on every VoIP server machines to check with the Raspberry Pi if there is a long enough power outage that the VoIP servers needed to be shut down (and automatically shut it down).</li>
  <li>Designing an <a href="https://medium.com/cermati-tech/centralized-cloud-identity-and-access-management-architecture-at-cermati-8d5f4ce4c0aa">IAM system</a> and developing its core component, called <a href="https://github.com/cermati/iamx">IAMX</a>. At this point, I was already heavier in management stuff than hands-on stuff, so the heavy lifting of the development to finish the system was done by my team members instead.</li>
  <li>Coming up with an idea of an internal phishing toolkit called Phisherman to enable us to perform <a href="https://medium.com/cermati-tech/adopting-an-offensive-approach-towards-raising-security-awareness-d0167636e3c0">phishing campaigns</a> with more flexibility. I didn’t get to do hands-on work on Phisherman’s implementation, but I’m happy that one of our security engineers could implement it well enough that it has been used for every single phishing-related offensive engagement we’ve been having ever since.</li>
</ul>

<p>There are other things I did, such as cloud infrastructure migration, leased line setup, and rearchitecting our cloud VPC for PCI-DSS compliance. And since starting in 2018, I was assigned to build and manage several teams, many of the later projects weren’t actually done by me myself, so the credit should really go to the team instead.</p>

<p>While I think I’ve been doing a management job way better than I initially expected, I somewhat miss the sense of satisfaction as an engineer when I managed to come up with a solution and deliver it myself (and then I can claim the achievement). As a manager, it feels a bit rude to claim an achievement the team achieved, even if it started from your idea, since you’re probably not the one who worked the hardest on it.</p>

<h1 id="reflection">Reflection</h1>

<p>Throughout my career, I was often confused when people asked me what I wanted to achieve. It’s a bit ironic because as a manager, that’s the exact question I always ask my team members and the candidates I interviewed in order to understand how I should work with them and align their goals with the team’s and the company’s goals.</p>

<p>The thing is, I mostly made my critical professional decisions in moments when:</p>

<ul>
  <li>I’m interested in trying something new, and the new project looks interesting enough.</li>
  <li>I need to step up and take more responsibility because the people around me (in this case, the company or the team) need it.</li>
</ul>

<p>So I can’t really say I’m someone with a long-term vision regarding my career trajectory, as my personal decision-making workflow really depends on what I think makes the most sense at a given moment. When there are multiple possible decisions that equally make sense, I’m going to just pick the one I find the most interesting.</p>

<p>I’d say the only areas I never really managed to get the hang of are front-end and mobile development. Despite having developed games in my university years, I quickly learned that I have no patience in making my games look good. This extends to my product development work, as I always needed a front-end engineer in the team to turn the half-assed, messy UI I implemented into something presentable to the users (unless they’ve provided me with all the standardized components and templates I could just reuse).</p>

<p>While I have been working in the infrastructure domain for the last 8 years, I’m still quite reluctant to really call myself an infrastructure specialist. This is due to the title of infrastructure engineer being used quite broadly; everybody from network engineers, sysadmins, cloud engineers, SREs, DevOps engineers, and platform engineers can claim that title. And I found that the terms like cloud engineer, SRE, DevOps engineer, and platform engineer are also used liberally in many situations, so I’m a bit afraid to set the wrong expectations for people when identifying myself as one.</p>

<p>I’m definitely <a href="/2025-06-09/you-shouldnt-learn-security-the-way-i-did">not a properly specialized security engineer</a>. I can do some security engineering work, and people I know tend to think that I’m somewhat an expert in cybersecurity. But I think I’m more of a software engineer who happened to know some cybersecurity due to having developed an interest in it relatively early and had some mischievous hacking streaks when I was younger.</p>

<p>Also, I don’t really prefer infrastructure over product development. I just happened to be interested in improving my infrastructure engineering capabilities at one point and ended up being the first infrastructure engineer of the team, and later on (reluctantly) becoming the team’s manager. If at some point I get offered to work on a product development project as an individual contributor, I think I’ll take it if my personal interest is taking the turn to go for more product-oriented projects at that point.</p>

<p>So if I have to summarize what I am and which direction I’m planning to go in a short sentence for a professional introduction, I might be struggling with that despite being a relatively senior tech worker at this point.</p>

<p>This is something I consider my biggest personal weakness, as I have been lacking a sense of a greater purpose at work. Many of the people I consider to be great in this field are the kind of people who have a greater purpose they’re trying to serve or a certain subdomain in the field they’re trying to be a master of.</p>

<p>When I was still early in my career, probably up to 5 years into it, people probably could brush off my lack of long-term direction and purpose as me still trying to discover myself in the exploration phase. But now I’m already 12 years into my career, and for me, it seems like exploring and looking for exciting things to do are all I want.</p>

<p>At least I noticed some differences between me and a few other people I know, whose primary purpose is also in getting excitement from work, and that is my tolerance for stressful situations and relatively boring work. After all, when at work, I have the mindset of, “I do what I’m paid for. If it’s what I’m paid for, then so be it.”</p>

<p>That probably allowed me to have relatively long tenures at the companies I’ve worked for so far, almost 4 years back at Bukalapak and already more than 8 years at Cermati. My guess, that probably what got me assigned to be a manager also.</p>

<h1 id="conclusion">Conclusion</h1>

<p>If there’s one thing from my experience so far that might be useful for aspiring software engineers, I’d say it doesn’t really matter how you start as long as you develop the right skills for performing the job. I didn’t know any Ruby on Rails when I started my first software engineering job (which used Ruby on Rails), but looking back, I totally crushed it there. I didn’t start as an infrastructure engineer, but now I’ve been doing infrastructure work for 8 years already, and so far I think I’m doing relatively well.</p>

<p>I started programming in high school with Visual FoxPro, a language and development tool set I never heard about again after I graduated high school. Nowadays I can code in various other programming languages. So it doesn’t really matter what programming language we start with, but choosing a programming language that’s more mature for the domain you want to work with definitely will help you get there faster. For example, if you want to be a front-end developer you probably have an advantage if you start with JavaScript, and if you want to be a data scientist you probably have an advantage if you start with Python.</p>

<p>I’ve met people who think that being able to do more than one thing well is unrealistic. I often saw them quoting Bruce Lee as follows.</p>

<blockquote>
  <p>“I fear not the man who has practiced 10,000 kicks once, but I fear the man who has practiced one kick 10,000 times.”<br />
— Bruce Lee</p>
</blockquote>

<p>The thing is, in that quote, Bruce Lee said that you’ll be way more effective using one kicking technique you have practiced 10,000 times than using the 10,000 kicking techniques you’ve only tried doing once. He’s definitely not saying that you only need to know just one kick. When he was alive, Bruce Lee must have had more than a few techniques he had trained extensively and could use effectively.</p>

<p>So, try to expand your knowledge and skill set as much as possible. But make sure you do it in a way you can enjoy.</p>

<h1 id="references">References</h1>

<p><a href="/2025-01-03/nothing-you-learn-is-useless">Nothing You Learn is Useless</a></p>

<p><a href="/2025-06-09/you-shouldnt-learn-security-the-way-i-did">You Shouldn’t Learn Security the Way I Did</a></p>

<p><a href="/2015-09-05/accidental-software-engineer">Accidental Software Engineer</a></p>

<p><a href="https://medium.com/cermati-tech/on-the-transition-from-being-an-individual-contributor-to-being-a-people-manager-af91282ab149">On the Transition from Being an Individual Contributor to Being a People Manager</a></p>

<p><a href="https://www.bloodshed.net/">Dev-C++ Official Website</a></p>

<p><a href="https://www.goodreads.com/author/show/3481230.Diki_Andeas">Diki Andeas</a></p>

<p><a href="https://en.wikipedia.org/wiki/Tifatul_Sembiring">Tifatul Sembiring</a></p>

<p><a href="https://rbates.dev/railscasts-retrospective-part-1-the-fuel">RailsCasts Retrospective Part 1: The Fuel</a></p>

<p><a href="/2025-06-04/how-i-built-an-anti-phishing-system">How I Built an Anti-Phishing System</a></p>

<p><a href="https://github.com/soundcloud/lhm">soundcloud/lhm: Online MySQL Schema Migration</a></p>

<p><a href="https://medium.com/cermati-tech/webrtc-integrating-cermatis-crm-system-with-telephony-infrastructure-2515ce43ff62">WebRTC: Integrating Cermati’s CRM System with Telephony Infrastructure</a></p>

<p><a href="https://medium.com/cermati-tech">Cermati Group Tech Blog – Medium</a></p>

<p><a href="https://medium.com/@sdsdkkk">Edwin Tunggawan – Medium</a></p>

<p><a href="/2017-06-23/docker-based-ansible-testing-environment">Docker-Based Ansible Testing Environment</a></p>

<p><a href="https://medium.com/cermati-tech/bcl-cermatis-cli-tooling-framework-and-simple-package-management-for-development-tools-5e5e3143969d">BCL: Cermati’s CLI Tooling Framework and Simple Package Management for Development Tools</a></p>

<p><a href="https://github.com/cermati/bcl">cermati/bcl: A derivation of SierraSoftworks’ Bash CLI</a></p>

<p><a href="https://medium.com/cermati-tech/working-with-a-physical-voip-infrastructure-as-a-software-engineer-73892c60c8ce">Working with a Physical VoIP Infrastructure as a Software Engineer</a></p>

<p><a href="https://medium.com/cermati-tech/centralized-cloud-identity-and-access-management-architecture-at-cermati-8d5f4ce4c0aa">Centralized Cloud Identity and Access Management Architecture at Cermati</a></p>

<p><a href="https://medium.com/cermati-tech/adopting-an-offensive-approach-towards-raising-security-awareness-d0167636e3c0">Adopting an Offensive Approach Towards Raising Security Awareness</a></p>]]></content><author><name>Edwin Tunggawan</name><email>vcc.edwint@gmail.com</email></author><category term="SoftwareEngineering" /><category term="Random" /><summary type="html"><![CDATA[After almost 12 years of professional experience]]></summary></entry><entry><title type="html">You Shouldn’t Learn Security the Way I Did</title><link href="https://sdsdkkk.github.io/2025-06-09/you-shouldnt-learn-security-the-way-i-did" rel="alternate" type="text/html" title="You Shouldn’t Learn Security the Way I Did" /><published>2025-06-09T00:00:00+00:00</published><updated>2025-06-09T00:00:00+00:00</updated><id>https://sdsdkkk.github.io/2025-06-09/you-shouldnt-learn-security-the-way-i-did</id><content type="html" xml:base="https://sdsdkkk.github.io/2025-06-09/you-shouldnt-learn-security-the-way-i-did"><![CDATA[<p>I’ve been getting quite a lot of video recommendations on YouTube on how to learn to hack and stuff. And after seeing a few of them, it reminds me of a few occasions when younger security practitioners asked me for some tips in learning to hack according to my experience.</p>

<p>The thing is, with all the cybersecurity learning resources today’s aspiring security engineers have, they have ways to learn cybersecurity concepts and technical fundamentals in ways I couldn’t do. And despite having worked to secure various systems so far, I’ve never really been a career security professional or security engineer. I was formally assigned the title of Security Engineer at Bukalapak at one point but I’d say I was still approaching the role the way a software engineer would, by hardening the application and implementing a few stuff.</p>

<p>I did learn to hack at some point. But I definitely don’t consider myself as a specialist in it, and it’s a bit hard for me to pinpoint the exact moments I actually learned to do so. It’s way easier for me to pinpoint the exact moments I actually found security holes in various systems with whatever knowledge I had at the time.</p>

<h1 id="high-school-years">High School Years</h1>

<p>During high school, I learned about sites such as <a href="https://www.hackthissite.org/">Hack This Site</a> and tried the challenges for a bit. But I don’t think that led me to anything useful.</p>

<p>The more useful stuff I learned might come from when in 2008 (or was it 2009?) I decided to install Ubuntu (I forgot which version) on the Windows XP PC my family had since 2003. Windows XP felt like it became slower over time, with the aging hardware possibly contributing to it. We didn’t have the budget for purchasing new hardware, and my high school IT teacher (whom I thought wasn’t really that good, just trying to throw some technical lingos to me to get me impressed) told me, “You’re not a real IT guy until you use Linux. But it’s hard, I warn you.”</p>

<p>I first installed Ubuntu using <a href="https://en.wikipedia.org/wiki/Wubi_(software)">Wubi</a>, and after a few more rounds of exploration, I decided to just ditch the Windows XP OS and install Linux Mint the normal way for the family to use.</p>

<p>Prior to ditching Windows XP, I did play around quite a lot with Windows XP’s multi-user management and directory permission settings and set up multiple accounts on the PC so each user could have their own personal directories with basic permissions on who could access what files and directories. Previously, my family all used the PC as a single user, with all files and data easily accessible to each other.</p>

<p>During this period, I also learned how to do batch scripting and made a few basic batch script viruses that caused a Windows PC to hang when running. I passed that around at the school’s computer lab during classes on a few class sessions, as I learned how to transfer files and exchange messages between Windows machines in the same LAN network remotely.</p>

<p>I also learned some programming with Visual Basic and Visual FoxPro around this time. But I couldn’t really make any malware at the time, despite learning to make a more sophisticated virus was my primary reason for getting into it.</p>

<p>I also used to hang around several Internet forums. This was the time when Friendster and MySpace were the leading social networking sites, and using real names on the Internet wasn’t the norm. I was involved in some Internet fights and online forum “gangs” at the time.</p>

<p>Using the few bits of information I have on everyone I know from their forum posts and their social media, I managed to find out their school and home addresses from a system owned by Indonesia’s Ministry of Education. I learned Google dorking at some point prior to this point in time, and I used Google dorking tricks to find out where I could get Excel files containing their data from the Ministry of Education’s public website.</p>

<h1 id="university-years">University Years</h1>

<p>During my first year of university at Universitas Multimedia Nusantara (UMN), one of my forum mates told me that another one of our forum mates was enrolled at the same university as me and we were both in the Computer Science program. I never realized that because the guy had been faking his photos in forum posts, and his social media profiles were fake. I was told his real name (not his full name, but his nickname and his last name) and due to this guy having problems with another one of our forum mates (a girl), I was asked to track down this guy in the university.</p>

<p>I found a photo of the guy in one of my major’s group pictures with his full name written under his face (added by the lecturer who took the photo so everyone could know each other). But I soon found out that guy only attended classes a few times and then went MIA, and he didn’t seem to have any social media accounts under his real name so that was all I could tell my forum mates about the guy.</p>

<p>I got Dr. Hargyo Tri Nugroho Ignatius (not a doctor yet back then) as my lecturer for my Computer and Network Security class back in my fifth semester. I really liked the class, as he used to be in some Indonesian black hat hacker group a few years back and he showed us quite a lot of practical hacking tricks in his classes. He also gave us assignments where we needed to find real vulnerabilities where we could exploit real systems in certain ways. From doing one of his assignments I managed to get admin access to an abandoned system owned by a well-known Indonesian company. He seemed to be acquainted with people like <a href="https://en.wikipedia.org/wiki/Jim_Geovedi">Jim Geovedi</a> and Juny Maimun (better known as Acong, the founder of Maxindo and Indowebster) from his hacking days, so I was definitely pretty privileged to have gotten him as my lecturer.</p>

<p>He, along with my senior at university, Dian Sandythia (better known as Sandy), who had interests in web application security and had experience exploiting real web applications, formed a security community at the university called INSECxT. I joined this community, and after Sandy showed us that our university’s academic information system contained IDOR and session fixation vulnerabilities, I played around with the academic information system and found a method I could use to extract the whole student body’s plaintext passwords from the academic information system by chaining the vulnerability.</p>

<p>I found a vulnerability where I could read my own plaintext password provided by the application’s backend, and I chained it with the IDOR and session fixation vulnerabilities demonstrated by Sandy to allow me to get the entire student body’s passwords. This was pretty bad, so I reported it to the university’s IT services department. They put some band-aid solution to prevent me from doing it the exact way I demonstrated to them, but I still could do it after that (in a way that fewer people know of). I always told people to not reuse any of their usual passwords for the university’s academic information system after that.</p>

<p>I also used to spend a lot of my free time at the university’s library, so I sometimes checked the library’s public computers for saved login credentials stored in browsers by previous users of the computers. I never used any of those credentials for malicious purposes, but definitely not something I should be proud of.</p>

<p>I learned about BackTrack Linux (now Kali Linux) and Metasploit from a seminar about computer security and hacking by Dr. Charles Lim (at the time not a doctor yet) from Swiss German University (SGU). I didn’t really try it much at this point, but I kept it in mind for later.</p>

<p>During my final year of university, one of the reasons I learned Ruby was because Metasploit was written in Ruby. The other reason was that I was a fan of <a href="https://www.goodreads.com/author/show/3481230.Diki_Andeas">Diki Andeas</a>, the author of Chickenstrip comic strip about a Linux and Ruby on Rails geek Indonesian software developer who wears a chicken costume. Learning Ruby led me to a job at Bukalapak, my first full-time job after finishing my undergraduate thesis.</p>

<h1 id="masters-degree">Master’s Degree</h1>

<p>So after I was done with my bachelor’s degree, I worked full-time at Bukalapak. I wasn’t doing a lot of security-related stuff around this time since I was saving up money to pursue my master’s degree at SGU to study computer and network security further since they provided a Master of Information Technology program with a concentration on cybersecurity (the popular term at the time was IT security and governance).</p>

<p>I was especially interested in their Offensive Security course which was taught by Dr. Benfano Soewito (who used to be my academic advisor for my first two semesters at UMN) and their Digital Forensics course which was taught by Dr. Charles Lim (the one who introduced me to BackTrack Linux and Metasploit a few years before).</p>

<p>The courses turned out to be quite a lot easier than I expected, so I was gathering my own learning resources from various sources. I found Carnegie Mellon University’s cybersecurity course materials, and writings from <a href="https://rocketreach.co/kim-guldberg-email_4577721">Kim Guldberg</a> and the late <a href="https://en.wikipedia.org/wiki/Adrian_Lamo">Adrian Lamo</a> on Quora as my references.</p>

<p>During my time as a master’s student at SGU, I managed to find a way to send unauthorized emails from SGU’s mail server and spoof the email senders. I reported it to the university and got it fixed.</p>

<p>I also found <a href="/2015-09-13/tokopedia-dos-vulnerability">a DoS vulnerability at Tokopedia</a> at the time. Leontinus Alpha Edison, the co-founder of Tokopedia, responded to my report personally at the time so I guess it might be as serious as I thought it was. I also started reporting vulnerabilities to a few other companies at the time, but without seeking bounty rewards since I was primarily a software engineer and made my living from that already.</p>

<p>I’m not sure when exactly this happened, but when I was doing my master’s study I somehow successfully planted a backdoor in one of the servers owned by a multi-level marketing business where quite a few students from UMN (where I did my bachelor’s degree) were recruited into the business.</p>

<h1 id="finally-graduating">Finally Graduating</h1>

<p>Only after I graduated with my master’s degree in late 2015, an infrastructure engineer at Bukalapak who also had interests in cybersecurity and had participated in several CTF competitions, Franheit Sangapta Manullang, told me about <a href="https://www.vulnhub.com/">VulnHub</a> and how I could find many VMs I could hack into for learning offensive cybersecurity legally. So I started doing a few VulnHub box challenges every now and then, and wrote writeups of the boxes I solved in this blog (you can see my past posts with “VulnHub … Writeup” title format).</p>

<p>At this point, I was no longer a student, so I started to be less aggressive in targeting real systems as I could no longer use the “I’m a student” get-out-of-jail card if people were to sue me for the more serious attacks I did. Also, since I already learned about VulnHub, I just used it whenever I was in the mood to take over some systems owned by other people.</p>

<p>I wrote <a href="/2016-07-23/safe-redirect-gem-for-rails">a Ruby gem called safe_redirect</a> to help secure Rails applications against open redirection vulnerabilities, which was one of the most commonly reported vulnerabilities I saw bug bounty hunters found. I also did some bug hunting for a few companies in my free time, but I never asked for bounty rewards so I never was a bounty hunter.</p>

<p>But one of the few attacks I seriously carried out against real systems after I graduated with my master’s degree was <a href="/2016-01-23/a-web-agencys-vulnerable-website">an attack against a friend’s web development agency’s CMS product</a>. I managed to find a vulnerability I could use to take over two of their registered businesses’ websites’ admin accounts, and I managed to push it further by figuring out who their clients were and took over some of these clients’ websites’ admin accounts with the same vulnerability.</p>

<p>I also built <a href="/2025-06-04/how-i-built-an-anti-phishing-system">an anti-phishing system</a> at Bukalapak where I practically developed and employed malware to take down phishing sites. I did some counteroffensive operations manually against some phishing sites while developing the system.</p>

<p>After resigning from Bukalapak and joining Cermati, I still did a few VulnHub box challenges but generally, I stopped doing offensive works since my interests shifted to something else. I learned a lot of electrical engineering, math, and statistics instead.</p>

<p>But at Cermati, I was assigned to build a security engineering team from scratch and there were a few offensive-leaning operations that the team has been doing under my direction. The more interesting ones are <a href="https://medium.com/cermati-tech/adopting-an-offensive-approach-towards-raising-security-awareness-d0167636e3c0">the internal phishing campaigns</a> where we use an in-house phishing toolkit we developed ourselves. There are also some <a href="https://medium.com/cermati-tech/simulating-a-cyber-attack-against-cermati-fintech-groups-call-center-facilities-594b4b6c9366">red teaming engagements</a> we do every now and then, which involve custom-made malware we prepared to avoid antivirus detection and to simulate the kind of attack we want to test our company’s resilience against.</p>

<h1 id="conclusion">Conclusion</h1>

<p>I’m mostly just a software engineer who happens to be a cybersecurity hobbyist and occasionally placed as the cybersecurity guy of the companies I’ve worked for. Looking at how I started learning cybersecurity and what I’ve been doing in the field, I didn’t exactly learn it in the most optimal, ethical, and legal way for specializing in it either.</p>

<p>Sure, it works for me and it helps the companies I’ve worked for so far. But I did quite a lot legally questionable stuff when I was learning, which I wouldn’t recommend other people doing, as it’s possible to unknowingly cause damage through our activities. Also, since I’ve mostly done it as a hobby or a pastime activity (especially when doing it outside work, and my work primarily hasn’t been cybersecurity), there’s a very good chance I’m technically lacking in things that should be considered as the standard expected knowledge or skillset of security engineers.</p>

<p>Given that the field of cybersecurity is maturing, and with more resources available for the younger generations who aspire to work in the field to learn it in a legal manner, there are definitely better ways to learn it that don’t require people to do what I did (and potentially with better results).</p>

<h1 id="references">References</h1>

<p><a href="https://www.hackthissite.org/">Hack This Site</a></p>

<p><a href="https://en.wikipedia.org/wiki/Wubi_(software)">Wubi (software)</a></p>

<p><a href="https://en.wikipedia.org/wiki/Jim_Geovedi">Jim Geovedi</a></p>

<p><a href="https://www.goodreads.com/author/show/3481230.Diki_Andeas">Diki Andeas</a></p>

<p><a href="https://rocketreach.co/kim-guldberg-email_4577721">Kim Guldberg</a></p>

<p><a href="https://en.wikipedia.org/wiki/Adrian_Lamo">Adrian Lamo</a></p>

<p><a href="/2015-09-13/tokopedia-dos-vulnerability">Tokopedia DoS Vulnerability</a></p>

<p><a href="https://www.vulnhub.com/">Vulnerable by Design ~ VulnHub</a></p>

<p><a href="/2016-07-23/safe-redirect-gem-for-rails">Safe Redirect Gem for Rails</a></p>

<p><a href="/2016-01-23/a-web-agencys-vulnerable-website">A Web Agency’s Vulnerable Website</a></p>

<p><a href="/2025-06-04/how-i-built-an-anti-phishing-system">How I Built an Anti-Phishing System</a></p>

<p><a href="https://medium.com/cermati-tech/adopting-an-offensive-approach-towards-raising-security-awareness-d0167636e3c0">Adopting an Offensive Approach Towards Raising Security Awareness</a></p>

<p><a href="https://medium.com/cermati-tech/simulating-a-cyber-attack-against-cermati-fintech-groups-call-center-facilities-594b4b6c9366">Simulating a Cyber Attack Against Cermati Fintech Group’s Call Center Facilities</a></p>]]></content><author><name>Edwin Tunggawan</name><email>vcc.edwint@gmail.com</email></author><category term="Security" /><category term="Random" /><summary type="html"><![CDATA[It's kinda illegal to do so]]></summary></entry><entry><title type="html">How I Built an Anti-Phishing System</title><link href="https://sdsdkkk.github.io/2025-06-04/how-i-built-an-anti-phishing-system" rel="alternate" type="text/html" title="How I Built an Anti-Phishing System" /><published>2025-06-04T00:00:00+00:00</published><updated>2025-06-04T00:00:00+00:00</updated><id>https://sdsdkkk.github.io/2025-06-04/how-i-built-an-anti-phishing-system</id><content type="html" xml:base="https://sdsdkkk.github.io/2025-06-04/how-i-built-an-anti-phishing-system"><![CDATA[<p>On a few occasions, I’ve been asked by people what I consider as the coolest thing I’ve built in my career as a software engineer up to the point the question is asked.</p>

<p>There are a few candidates on which project I consider the coolest. But if we speak in terms of the impact the project had to the regular non-techie Internet users, then the anti-phishing system I built back when I was working at Bukalapak should be up there on the list.</p>

<p>This is a system I rarely talk about in detail, considering that if I disclose the approach I used then the phishers can learn how to disable the trap I set up for them. But considering that <a href="https://jakartaglobe.id/business/bukalapak-ceases-most-ecommerce-operations-shifts-to-utility-payments-amid-stock-decline">Bukalapak closed down their C2C e-commerce business</a> where I did the entirety of my work when I was there, and how I noticed that the phishing trends have been evolving in the past 10 years, I think disclosing some of the tricks I used when implementing the anti-phishing system now might not impact the security of their current users significantly. It should also be educational for software engineers as a trick they can deploy for securing their systems, or for security engineers when trying to counter some kind of attacks.</p>

<h1 id="background">Background</h1>

<p>Bukalapak used to be one of the biggest C2C e-commerce sites in Indonesia, and one of the first local e-commerce sites with a built-in escrow service (which I believe Tokopedia had before us, but Bukalapak already had it for some time when I joined them in August 2013). Our escrow service requires us to refund the funds to the buyers for transactions that are canceled by the sellers or the items are returned by the buyers, and we must forward the funds to the sellers for transactions that are successfully completed.</p>

<p>Because back in the early 2010s our banks hadn’t yet provided good banking infrastructure for e-commerce systems with payment API integration and such, initially we needed to do fund transfers manually. And as we scale, we needed to use various workarounds to automate fund transfers for the major banks we supported. This is because we were forwarding the funds directly to the bank accounts configured by the sellers and buyers for their fund transfers immediately after each transaction.</p>

<p>At one point, we decided to just pool the funds in our system (under a feature called BukaDompet) until the users specifically requested the funds to be transferred to their configured bank accounts. This decision was made for two reasons:</p>

<ul>
  <li>Reducing the number of fund transfers we need to perform daily, by allowing the funds from multiple completed transactions to be transferred to the users’ bank accounts in batches by the users’ demand instead of directly transferring them after each transaction. This makes it more efficient for our system to handle the load of transferring the funds to the users’ bank accounts.</li>
  <li>Allowing the funds to be pooled in the users’ Bukalapak accounts should encourage the users to shop more on the site as they could just use their BukaDompet balance to pay for transactions in Bukalapak instead of having to do more manual bank transfers when paying for the transaction (bank transfer was the most prominent payment method used by Indonesians when shopping online).</li>
</ul>

<p>This sounds good as it reduced our operational workload for doing fund transfers to the users’ bank accounts and pushed the users to spend more on our e-commerce site. But here comes the problem: it gave an incentive for cybercriminals to try and hijack our users’ Bukalapak accounts, and then drain the funds the users had in their BukaDompet wallet.</p>

<p>So we started having to deal with financially-motivated phishing attacks targeting our users.</p>

<p>There were solutions such as two-factor authentication that we implemented at the time. But due to various reasons, the effectiveness wasn’t really where we wanted it to be. We probably could make it more effective if we made it mandatory, but back then we were still aiming for high growth on various fronts so we were quite reluctant to push it since it might reduce the user and transaction conversion.</p>

<p>Nowadays most e-commerce sites operating in Indonesia are alright with making things a bit inconvenient for users in order to make their systems more secure, but back then it wasn’t really the case.</p>

<p>In the context of this post, I’ll discuss how I came up with a system that could automatically take down most phishing sites targeting our users within one hour after the phishing site’s initial deployment.</p>

<h1 id="how-the-problem-and-solution-evolved">How the Problem and Solution Evolved</h1>

<p>The anti-fraud operations team was the first people to notice and deal with the phishing problem. They started getting reports from users that their accounts were compromised, and they started dealing with it. After noticing that there were more cases than they could anticipate without support from the engineering team, the lead of the anti-fraud team went to my desk to tell me about the problem they were dealing with.</p>

<p>We had no idea how massive the phishing operations targeting our users were at the time. But based on the cases reported to the anti-fraud team by the victims, I could figure out a few patterns on how the phishing sites were set up.</p>

<ul>
  <li>The phishing sites tend to use variations of the string “bukalapak” on their URLs.</li>
  <li>After the users enter their login credentials on the phishing sites, the sites will redirect the users to the real Bukalapak site.</li>
</ul>

<p>Based on this information, I set up a system to keep track what sites that have suspicious variations of the “bukalapak” string had redirected users to our site, and set up a dashboard for the anti-fraud operations team to monitor if they encounter anything they considered phishing sites.</p>

<p>To make the life of the phishers harder, I also set up a few scripts I could run from my work computer to spam fake username/password pairs to fill the phishing site’s DB with fake data and waste the attacker’s time.</p>

<p>I analyzed a few of the phishing sites the anti-fraud team found from user reports, and I noticed a pattern that most of the phishing sites we found were storing the credentials of their phished victims in a text file that can be accessed as long as we know the text file’s path in the sites. So we could retrieve the list of phishing victims to notify them and help them secure their online accounts.</p>

<p>Some of the later versions of the phishing site template seemed to have changed the location of the text file since I encountered a few exact same phishing sites but with the credentials written to a text file stored under a different name. But after I figured out those also, the phishers started to make things even harder as they started to get better in hiding those text files so we couldn’t recover the list of victims from the later phishing sites.</p>

<p>The sites were hosted using various website hosting providers that provided free hosting packages, so I taught the anti-fraud operations team (they weren’t really tech people, but could be quite savvy) how to figure out which hosting provider was used by a certain phishing site and how to find the email contact for reporting phishing sites hosted on their infrastructure. The hosting providers would take down the sites after we reported it, but some providers seemed to be ignoring our messages. Luckily, most of the phishing sites were hosted using the more responsive providers.</p>

<p>After a while, I noticed that more than 90% of the phishing sites we detected were hosted on only three or four hosting providers (and all of them are pretty responsive). So I set up our system to do a pattern matching on the URLs of the phishing sites that were redirecting their victims to our sites to identify which hosting provider was used, and had our system automatically send an email to those providers asking for the sites to be taken down.</p>

<p>This actually worked very well, since a lot of the phishing sites were taken down very quickly after it was detected to have redirected traffic to our system. Some of them seemed to be taken down from the traffic of the phishers getting redirected to our site when testing the phishing sites before sending it to real victims.</p>

<p>But having their phishing sites taken down too quickly seemed to have alerted the phishers that we had something that could take down their phishing sites very quickly, and they seemed to have experimented with a few setups to avoid their sites getting detected and taken down. It ended up with them deploying phishing sites that didn’t redirect traffic to our site after the victims submitted their credentials to the malicious sites, and the anti-fraud team started getting reports of phishing sites that weren’t detected by our phishing site detector.</p>

<p>So here I made the final modification to the anti-phishing system (the final modification I did before I left the company, at least). After analyzing all the reported phishing sites, I found that the vast majority of them were copying and pasting our HTML code directly, referencing the same JavaScript, CSS, and image assets URLs used on our real site. There were a few phishing sites that didn’t do such things, but these sites visually didn’t resemble our site’s login page at all so fewer users were fooled.</p>

<p>With that information, I added a backend API endpoint whose URL was disguised as a JavaScript asset URL. In our front-end JavaScript code, I slipped several lines of code that check if the JavaScript was run on a browser that was opening our real website by checking the domain of the opened site. If it was not our site, then it would trigger an API call to the disguised endpoint, sending us information about the site that ran the JavaScript code to be checked by our anti-phishing system. If it was considered malicious, the anti-phishing system would automatically send an email to the hosting provider where that site was hosted, requesting a takedown of the site.</p>

<p>Up until I left the company, it seemed to have solved most of our phishing problem. The final modification I made practically made our front-end JavaScript code a malware that automatically takes down phishing sites if it were to be reused by phishers to make their phishing sites look and feel authentic. At that point, most phishing sites could be detected by our system during its initial deployment as soon as the site was rendered by the phisher when making sure that it was already live, and then our system would send an email to the site’s provider asking it to be taken down. Most of the detected phishing sites were taken down within 30-60 minutes.</p>

<h1 id="what-happened-after-i-left">What Happened After I Left</h1>

<p>I’d never heard about Bukalapak facing a phishing crisis at such a large scale after I left, so I simply assumed that the anti-phishing system I developed and set up was sufficient. Probably they needed to add minor adjustments here and there, especially on the phishing site detection logic and the module that sends phishing site takedown requests to hosting providers.</p>

<p>The Indonesian government issued a regulation that banned local e-commerce sites from providing e-wallet features such as BukaDompet some time after I left, so in the end the BukaDompet balance of the users was moved to DANA, an Indonesian e-wallet company that’s quite close to Bukalapak since they are both part of the EMTEK Group’s investment portfolio. This shifted the responsibility to manage and secure the wallet balance to DANA, so I think Bukalapak users should be at less risk of getting targeted by phishers after that.</p>

<h1 id="conclusion">Conclusion</h1>

<p>Would that solution be feasible for today’s phishing attacks? It’s a bit hard to tell since at Cermati I’ve never worked on projects where I should protect our end users from phishers, so I definitely have been missing contexts on what phishing attacks targeting a web-based application’s end users would look like today.</p>

<p>I did see a few phishing attempts while working at Cermati, never a site targeting our end users, but they were built and executed very differently from what I saw at Bukalapak. So I don’t think the tricks I used at Bukalapak will work in this case.</p>

<p>But from what I’ve seen in the wild, I think local cybercriminals have shifted to targeting the victims’ phones instead of simply compromising their e-commerce or e-wallet accounts. I’ve seen the rise of reports from people who were sent APK files via WhatsApp by people impersonating a delivery guy or someone they know, trying to fool them that the APK files are some other kind of files.</p>

<p>I also helped a friend who might have gotten love scammed last year, where they were tricked by their supposed “lover” into installing a phony TikTok Shop app on their device in order to get some extra income. They were told to deposit money to a bank account owned by TikTok as instructed by some phony TikTok customer service staff, they were told that this allowed them to be a premium seller or something for TikTok Shop’s newly opened Australia region and TikTok Shop would handle all the item stock, delivery, and some other stuff. Sounds too good to be true? Of course it is, since it’s not real and that’s now how being an e-commerce seller works.</p>

<p>They lost practically all their life savings from that scam, they initially contacted me to borrow some money but since I felt like what they described to me was plenty suspicious, I decided to investigate it for a bit and reverse-engineered the TikTok Shop app they were asked to install by their “lover.” It had some pretty funny modules in it that weren’t supposed to be in a real TikTok app, and they downloaded it from some random AWS S3 bucket instead of the Google Play Store.</p>

<p>While phishing is still a thing, I think for targeting end users, cybercriminals tend to use even more sophisticated tricks nowadays.</p>

<h1 id="references">References</h1>

<p><a href="https://jakartaglobe.id/business/bukalapak-ceases-most-ecommerce-operations-shifts-to-utility-payments-amid-stock-decline">Bukalapak Ceases Most E-Commerce Operations, Shifts to Utility Payments Amid Stock Decline</a></p>]]></content><author><name>Edwin Tunggawan</name><email>vcc.edwint@gmail.com</email></author><category term="SoftwareEngineering" /><category term="Security" /><summary type="html"><![CDATA[Basically a malware that destroys the phishing site]]></summary></entry><entry><title type="html">AI and Modern Workforce</title><link href="https://sdsdkkk.github.io/2025-05-23/ai-and-modern-workforce" rel="alternate" type="text/html" title="AI and Modern Workforce" /><published>2025-05-23T00:00:00+00:00</published><updated>2025-05-23T00:00:00+00:00</updated><id>https://sdsdkkk.github.io/2025-05-23/ai-and-modern-workforce</id><content type="html" xml:base="https://sdsdkkk.github.io/2025-05-23/ai-and-modern-workforce"><![CDATA[<p>I was invited to be a panel speaker for a session at the <a href="https://techmind.id/event/3rd-festival-of-digital-innovation-fdi-bsd-2025/">Festival of Digital Innovation</a> event in BSD, South Tangerang. I was set to be in a discussion session with Fetri Miftach from Xynexys, Yusri Amsal from PwC, and Rendra Perdana from DANA, where the session was moderated by James Lim from Centre for Cybersecurity Institute, Singapore.</p>

<p>This post was written on the night after the event.</p>

<p>I was a last-minute addition to the panel, so probably that’s why I’m the only one from the session whose name and picture aren’t listed on the event landing page. But hey, the organizer at least made promotional images with my face on them:</p>

<ul>
  <li><a href="/images/posts/fdi-icion-01.jpg">Solo promotional image</a></li>
  <li><a href="/images/posts/fdi-icion-02.jpg">Group promotional image</a></li>
</ul>

<p>The images are pretty big and irrelevant to what I’m going to write here, so I’ll settle with linking to those images instead of rendering them here.</p>

<p>The topic of the panel discussion was mostly about how AI is affecting work and also the workforce, and how we expect workers and students to adapt to a future of work with AI. In this post, I’m putting a few points I brought in the panel discussion in a written form so my friends who might be interested in the points discussed in the session can refer to this if needed.</p>

<p>I know at least one friend who seemed interested after I told them about my view on one of the points that were brought up by the moderator, so writing it down might be a good idea.</p>

<p>I’m writing it in a Q&amp;A format since that was how the discussion was carried out. But I’ll just focus on the relevant questions and what I think about the issue, since I probably wouldn’t be able to represent the other panel speakers’ opinions accurately (assuming I even remember them all correctly).</p>

<h3 id="does-the-rise-of-ai-technologies-change-the-criteria-youre-looking-for-in-candidates-youre-hiring-for-your-team">Does the rise of AI technologies change the criteria you’re looking for in candidates you’re hiring for your team?</h3>

<p>With or without AI, what I consider a strong candidate should have:</p>

<ul>
  <li>Strong understanding of the fundamentals of their field of expertise</li>
  <li>Strong reasoning capabilities to navigate various situations and to make decisions</li>
</ul>

<h3 id="what-should-academia-do-to-keep-up-with-the-latest-ai-technologies-considering-it-seems-that-academia-is-lagging-in-preparing-their-students-to-leverage-ai">What should academia do to keep up with the latest AI technologies, considering it seems that academia is lagging in preparing their students to leverage AI?</h3>

<p>Not just limited to AI, the academia lagging behind the industry in adapting to new technologies isn’t something new. We’ve heard people complaining about academia teaching outdated concepts and technologies to students for decades.</p>

<p>I happened to have met and talked with faculty members from two different universities on two separate occasions within the last 6 months or so. From the discussions I had with them, I found that both universities had basically the same problem: how they can teach the latest industry trends to their students.</p>

<p>I can understand that they want to make sure their students can easily adapt to the industry demands after the students graduate from those universities. But I think they’re approaching it the wrong way.</p>

<p>People always complain that universities are teaching outdated technologies and practices. That’s to be expected since many university lecturers don’t do full-time work in the industry (except for the adjunct lecturers, who might be expected to have a full-time industry job but probably less involved with the students) so it’s unreasonable for us to expect them to keep up with the industry trends while the industry itself is changing so fast. We have new tools popping up at a very fast rate, the existing tools changing rapidly with new version releases, and ever-alternating industry practice trends.</p>

<p>Given the number of faculty members and lecturers a university can have at one time, it’s unrealistic for them to be that up-to-date with the industry. Universities with more resources probably can do a better job in keeping up with the industry, but even then they still can only cover relatively little of the ever-changing industry trends.</p>

<p>I think the better approach is for the university to focus on teaching their students the fundamentals and make sure their students understand it properly. After all, once someone understands the fundamentals, they should be able to derive the necessary skills for them to adapt to the latest trends from there.</p>

<h3 id="given-that-ais-can-learn-very-fast-how-do-you-think-we-should-keep-up-with-ai-since-it-takes-way-more-time-for-humans-to-learn-a-skill-if-compared-to-ai-what-should-academia-do-to-allow-students-to-not-be-outcompeted-by-ai">Given that AIs can learn very fast, how do you think we should keep up with AI since it takes way more time for humans to learn a skill if compared to AI? What should academia do to allow students to not be outcompeted by AI?</h3>

<p>AI can learn at a superhuman speed given the resources and can accumulate knowledge at a rate that no human can compete with.</p>

<p>But when the AI is wrong, it’s never the AI whom we think to be the one at fault. It’s always someone else, maybe the AI’s developers or users. The blame never goes to the AI itself.</p>

<p>The AI won’t care how many mistakes it has made, and there are no real consequences for itself when making those mistakes. With the current AI technology, at least, we can’t really punish misbehaving AI to make it feel regret and have the AI live with that regret.</p>

<p>Humans are different. They can be punished, their reputation will suffer when they make mistakes, and  they will also suffer from it. Unlike AI, humans must live with whatever mistakes they have made in the past.</p>

<p>Hence, humans have a lot more at stake when performing actions and making decisions, which AI doesn’t have. As long as humans have these characteristics (and as long as AI doesn’t have them yet), there should always be jobs where a human is the better choice to do it.</p>

<h1 id="references">References</h1>

<p><a href="https://techmind.id/event/3rd-festival-of-digital-innovation-fdi-bsd-2025/">3rd Festival of Digital Innovation (FDI) - BSD 2025</a></p>]]></content><author><name>Edwin Tunggawan</name><email>vcc.edwint@gmail.com</email></author><category term="ComputerScience" /><category term="Management" /><summary type="html"><![CDATA[Humans are still irreplaceable, at least for now]]></summary></entry><entry><title type="html">I Guess I Used Wails the Wrong Way</title><link href="https://sdsdkkk.github.io/2025-05-03/i-guess-i-used-wails-the-wrong-way" rel="alternate" type="text/html" title="I Guess I Used Wails the Wrong Way" /><published>2025-05-03T00:00:00+00:00</published><updated>2025-05-03T00:00:00+00:00</updated><id>https://sdsdkkk.github.io/2025-05-03/i-guess-i-used-wails-the-wrong-way</id><content type="html" xml:base="https://sdsdkkk.github.io/2025-05-03/i-guess-i-used-wails-the-wrong-way"><![CDATA[<p>Recently, I was looking at <a href="https://wails.io/">Wails</a> as an option to build a hobby project I was thinking about. I planned to build a desktop application that can take a webcam input stream, and based on the movement of the person captured in the camera, then move some objects rendered by the application on the screen.</p>

<p>At work, my team has been using Wails to develop a desktop GUI client for one of our internal platforms that needs to alter some settings in the client machine when used. Many of the users of this platform aren’t technical users, hence we need to provide GUI. Also, the users are using different operating systems on their machines, so we need to be able to support Linux, Mac OS, and Windows.</p>

<p>Initially, we built the front-end using <a href="https://www.electronjs.org/">Electron</a>. But as we started using Golang more for our back-end, we decided to move to Wails so we could reuse the server code written in Golang in our client implementation.</p>

<p>Wails can also use React front-end with TypeScript, which makes it a relatively interesting choice for me to use in my hobby project since I haven’t been coding much at work as my work becomes heavier on managing)(and across multiple domains so by itself it already involves a lot of context-switching), and I have never been very up-to-date with front-end development technologies.</p>

<p>Sounds like an obvious choice for me to use while improving my knowledge of the framework my team uses at work, right?</p>

<p>…</p>

<p>Hoo boy, was it a mistake.</p>

<p>While I didn’t really encounter meaningful problems doing the regular React and Golang parts of Wails, I think the way it was built for workflows similar to client-server communication between web browsers and web servers (after all, Wails front-end is just a web app rendered on a browser engine) made it a poor fit for the project I had in mind.</p>

<p>Continuously sending processed webcam frame images from the back-end to the front-end to be rendered by the React front-end was pretty slow and eventually caused the application to hang. Also, the front-end was a bit laggy when updating the webcam stream images because I was using the <code class="language-plaintext highlighter-rouge">&lt;img&gt;</code> tag to render the webcam frames and updating the image with a set interval from the front-end.</p>

<p>Probably I should’ve used the <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code> tag instead, which I’ve never used before, but then I might need to adjust the implementation of the webcam image capture and processing flow to allow it to be streamed as video for the React front-end.</p>

<p>I ended up deciding to just drop the idea of using Wails for the project and just use C++ with OpenCV instead. And <a href="https://github.com/sdsdkkk/camface">it immediately worked</a>. Also, I ended up using OpenGL to draw the object to be controlled with the webcam input <a href="https://github.com/sdsdkkk/vobject-controller">and make it 3D</a> instead of 2D as I initially planned to do with Wails.</p>

<p>I had this idea of changing the direction of <a href="https://github.com/sdsdkkk/camface">the project</a> into a robot that can automatically aim and shoot people who are close enough to the camera instead (I saw a YouTube video of someone building this stuff a few years ago). But then I might need to build my own custom robotic parts, which might be a bit too complicated for me to want to invest my time in it for the time being, so I decided to just move forward with my original plan of making an object that’s controllable via camera input.</p>

<p>Anyway, I think this is the first time I touched C++ since I graduated from university. I believe last time I used C++ was in my Computer Graphics course where we got assignments to draw things with OpenGL using C++, and I never came back to it after that.</p>

<p>I did use C occasionally, such as when contributing a minor feature to the <a href="https://github.com/sdsdkkk/dump1090_sdrplus">dump1090_sdrplus</a> project to allow it to export the data captured by my <a href="https://www.rtl-sdr.com/">RTL-SDR</a> dongle into a CSV file. I believe that was the only time I contributed to any software project written in C though, the rest of my C usage was just me making toy Linux kernel modules for my own purposes.</p>

<h1 id="references">References</h1>

<p><a href="https://wails.io/">The Wails Project</a></p>

<p><a href="https://www.electronjs.org/">Electron</a></p>

<p><a href="https://github.com/sdsdkkk/camface">GitHub - sdsdkkk/camface</a></p>

<p><a href="https://github.com/sdsdkkk/vobject-controller">GitHub - sdsdkkk/vobject-controller</a></p>

<p><a href="https://github.com/sdsdkkk/dump1090_sdrplus">GitHub - sdsdkkk/dump1090_sdrplus</a></p>

<p><a href="https://www.rtl-sdr.com/">RTL-SDR</a></p>]]></content><author><name>Edwin Tunggawan</name><email>vcc.edwint@gmail.com</email></author><category term="SoftwareEngineering" /><category term="Random" /><summary type="html"><![CDATA[And so, I finally went with C++]]></summary></entry></feed>