<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Rida F&#39;kih on Medium]]></title>
        <description><![CDATA[Stories by Rida F&#39;kih on Medium]]></description>
        <link>https://medium.com/@ridafkih?source=rss-9c88105465dc------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*Cc_eV81zG0KbpFTq</url>
            <title>Stories by Rida F&amp;#39;kih on Medium</title>
            <link>https://medium.com/@ridafkih?source=rss-9c88105465dc------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 22:55:13 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@ridafkih/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Nothings Chats is Not Secure.]]></title>
            <link>https://medium.com/@ridafkih/nothings-chats-is-not-secure-281d71b9cf52?source=rss-9c88105465dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/281d71b9cf52</guid>
            <category><![CDATA[tech]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[startup]]></category>
            <dc:creator><![CDATA[Rida F'kih]]></dc:creator>
            <pubDate>Sat, 18 Nov 2023 08:21:27 GMT</pubDate>
            <atom:updated>2023-11-18T16:06:39.394Z</atom:updated>
            <content:encoded><![CDATA[<h3>‘Nothing Chats’ is Not Secure.</h3><p>Outlining security risks in ‘Nothing Chats,’ an iMessage app for Android made in partnership with ‘Sunbird’. Observe the poor security practices that made it into the production release.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dBenrrUyxhYHFjYghRs4sg.png" /><figcaption>‘Nothing Chats’ is an application released by Nothing in partnership with Sunbird, bringing iMessage to Android but littered with security flaws.</figcaption></figure><p>You can read about our findings of ‘Nothing Chats’ post on the Texts.com blog at <a href="https://texts.blog/2023/11/18/sunbird-security/">https://texts.blog/2023/11/18/sunbird-security/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=281d71b9cf52" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Re-Wrote These 10+ Single Lines of JavaScript Code, the Team Lead Praised the Code for Being…]]></title>
            <link>https://levelup.gitconnected.com/i-re-wrote-these-10-single-lines-of-javascript-code-the-team-lead-praised-the-code-for-being-668ade4fea71?source=rss-9c88105465dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/668ade4fea71</guid>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Rida F'kih]]></dc:creator>
            <pubDate>Thu, 20 Oct 2022 04:47:40 GMT</pubDate>
            <atom:updated>2022-10-27T23:13:20.227Z</atom:updated>
            <content:encoded><![CDATA[<h3>I Re-Wrote These 10+ Single Lines of JavaScript Code, the Team Lead Praised the Code for Being Elegant</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*bjyhMSpV5nxkKCTBhLV1Jw.gif" /><figcaption>It’s not a phase, mum.</figcaption></figure><p>I am the Team Lead, I praised the code. /s</p><p>This post is in response to, but by no means a dig on the blog post written by Zard-x on Medium called ‘<a href="https://javascript.plainenglish.io/i-wrote-these-10-single-lines-of-javascript-code-the-team-lead-praised-the-code-for-being-elegant-6a9c471a9613">I Wrote These 10+ Single Lines of JavaScript Code; the Team Lead Praised the Code for Being Elegant</a>’.</p><p>One-liners are really cool challenges and very fun to make. I used to spend a lot of my time on <a href="http://codewars.com/">codewars.com</a> and <a href="http://codingame.com/">codingame.com</a>, which are two websites that facilitates little coding challenges which challenge your ability to write short code, or write code fast.</p><p>While code golf can serve as a fun engineering exercise, their lessons should rarely be used in the real world — and when they are — by no means should engineering managers be promoting developers to use this type of code in a codebase. When you’re in a collaborative environment, writing <em>good code</em> should be a priority. That means code that is readable, maintainable, and runs reliably.</p><blockquote><em>Code golf is a type of recreational computer programming competition in which participants strive to achieve the shortest possible source code that solves a certain problem.</em></blockquote><blockquote>— Wikipedia, Code golf</blockquote><h3>Array Deduplication</h3><h4>Original Source Code</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/190e4296dc1569597b10addc6c670386/href">https://medium.com/media/190e4296dc1569597b10addc6c670386/href</a></iframe><p>I’m not necessarily opposed to the common trick of removing duplicates from arrays by instantiating, and spreading a set, but due to the amount of times you’re indexing the array, it can be quite poor performance-wise.</p><h4>Rewritten Source Code</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d6d94a051279d492c456ed32bd3d56a7/href">https://medium.com/media/d6d94a051279d492c456ed32bd3d56a7/href</a></iframe><p>On an array of 1,000,000 randomly generated numbers between 1–100, the original source code only performs at 12% of the speed that the rewritten version does. Since we use a map in the second function, we only have to iterate once over the array, and made it so that checking to see if we’ve already seen an element takes O(1) time.</p><p>The code eliminates “tricks,” and instead implores a well-known concept like hash maps, which may reduce the occurrence of inquiries by other developers on your code. The code also has well-named variables, with the function name removeDuplicateStrings defining the action that the function is doing, rather than an ambiguous name like uniqueArr, it also does not use excessively abbreviated words, making the code easier for non-native English speakers to understand.</p><p>Notice that the function is not documented. Excessive documentation can sometimes be a bad thing. If your variable names are well named, you may find your comments redundant, and that’s a good thing! If that happens, happily drop ’em, and ship it!</p><p>If we’re absolutely dead-set on using spread operators and sets, or we want to remove duplicates of values that are not exclusively strings without writing bloated functionality, all we need to do is document our code, and ensure our variables are well-named.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/21a8b7f43f16e400d9126087869a699a/href">https://medium.com/media/21a8b7f43f16e400d9126087869a699a/href</a></iframe><h3>Get Parameters from a URL and Convert Them to Object</h3><h4>Original Source Code</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/595c43cd37351aa15d8e60844b71c34e/href">https://medium.com/media/595c43cd37351aa15d8e60844b71c34e/href</a></iframe><p>If there was a bug with this code, how excited would you be when you figured out this is the function you’d be working on? Odds are, not so much. Not to mention that re-building JSON objects with strings is something you want to avoid as much as possible, in this case that’d be quite easy.</p><h4>Rewritten Source Code</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2f761cbc3445d979e97671c49a7564f3/href">https://medium.com/media/2f761cbc3445d979e97671c49a7564f3/href</a></iframe><p>In the rewritten code for this function, we use the convenient native JavaScript URL API which automatically invokes an instance of the URLSearchParams object for us, then we simply use the Object#fromEntries function on the resulting object! This prevents us from having to manually construct a JSON object by mingling and mangling strings.</p><p>Notice that we’ve provided a comment for this function! Despite the fact that I’ve included a specification for which <strong>type</strong> of parameters the function handles in the name of the function getURLParameters, it’s not necessarily clear what format the resulting object would be in.</p><h3>Check Whether the Object is Empty</h3><h4>Original Source Code</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2dda5431b9f201ef8e73801e60b26093/href">https://medium.com/media/2dda5431b9f201ef8e73801e60b26093/href</a></iframe><p>Using ownKeys or Object.keys are both not very performant when checking if an object is empty.</p><h4>Rewritten Source Code</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f209b38d788945ffa44ceecebd3139e4/href">https://medium.com/media/f209b38d788945ffa44ceecebd3139e4/href</a></iframe><p>This rewritten code is an old school method, and man has it passed the test of time! The re-written source code performs 20 times faster than the original method, and that’s only with two properties on an object. The performance boost comes from the fact that you no longer need to create arrays, copy over values, and index keys. You see one key and you’ve escaped the function!</p><p>It might not immediately be obvious why we’re iterating over the keys of the object, so we’ve left a short comment in there to ensure that any other developers know what’s going on.</p><h3>Reverse the String</h3><h4>Original Source Code</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/04d9327b552c320a6d1ed29a91a38088/href">https://medium.com/media/04d9327b552c320a6d1ed29a91a38088/href</a></iframe><p>In this case, we’re not off to a bad start! We <em>could</em> use a for-loop to get an 80% performance boost on short strings, and we might consider implementing that method if we’re reversing some chunky strings often, but in the case of the odd reversal on lightweight strings, we might just be better off with this functionality.</p><h4>Rewritten Source Code</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6d941a4602a7661b24459a6281bd3d78/href">https://medium.com/media/6d941a4602a7661b24459a6281bd3d78/href</a></iframe><p>Splitting the chained methods across multiple lines is a personal preference of mine, as it allows me to scan the function paths rather than jumping through them, however if someone asked me to change it I wouldn’t make a fuss.</p><p>For fun, here is a more performant version.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2fc230f71346786b6c052d9546b6a282/href">https://medium.com/media/2fc230f71346786b6c052d9546b6a282/href</a></iframe><h3>Generate Random Hex</h3><h4>Original Source Code</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/701586549eddb927d005519f306d0af8/href">https://medium.com/media/701586549eddb927d005519f306d0af8/href</a></iframe><p>Once again, not off to a bad start! I particularly like that we’re directly referencing the maximum hexadecimal value supported for non-alpha colours! Some minor cleanup, and we’ll be in business!</p><h4>Rewritten Source Code</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4bd3f532ea54b8084e1659eb9b1c55c3/href">https://medium.com/media/4bd3f532ea54b8084e1659eb9b1c55c3/href</a></iframe><p>The only major change I made in this example is that I changed padEnd to padStart. The way this function works is by generating a random 24-bit integer, and then representing it in its hexadecimal format.</p><p>The minimum value we can get is 0 0x000000, with the highest value being 16,777,215 0xFFFFFF.</p><p>Let’s say our randomValue ended up being 255. Our hexValue would then be ff, and if we padded the end, our return value would be #ff0000, versus if we padded the beginning it would be #0000ff. If we then translate both these values back into integers, #ff0000 would actually represent the value 16,711,680, while #0000ff would represent 255. This means that if we pad the end rather than the beginning, we’d effectively get the wrong value.</p><p>In addition to this fact, with the first method, by padding the end rather than the beginning, #0000ff would actually be impossible to generate. Meaning there are plenty of missing values that could not possibly be generated. Specifically, every value between 0x000001 and 0x100000. That is 1,048,576 missing values from our function, but would also tip the odds in favour of all values that end with a 0, some more than others. For example, #100000 would be the result from 0x1, 0x10, 0x100, 0x1000, 0x10000, and of course 0x100000.</p><h3>Conclusion</h3><p>That took longer than expected, so I’ll be posting a second part to this blog post at a later date. I had a ton of fun refactoring this code. Would you have done something differently? Leave a comment on <a href="https://medium.com/@ridafkih/i-re-wrote-these-10-single-lines-of-javascript-code-the-team-lead-praised-the-code-for-being-668ade4fea71">Medium</a> or <a href="https://dev.to/rida/i-re-wrote-these-10-single-lines-of-javascript-code-the-team-lead-praised-the-code-for-being-elegant-ec">dev.to</a>! I think this is a great learning opportunity for everyone, and I value all feedback!</p><p>Want to read more of my stuff? You can check out my <a href="https://rida.dev/">personal website</a>. If you’d like to start a dialogue, feel free to <a href="https://twitter.com/ridafkih/">tweet at me</a>!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=668ade4fea71" width="1" height="1" alt=""><hr><p><a href="https://levelup.gitconnected.com/i-re-wrote-these-10-single-lines-of-javascript-code-the-team-lead-praised-the-code-for-being-668ade4fea71">I Re-Wrote These 10+ Single Lines of JavaScript Code, the Team Lead Praised the Code for Being…</a> was originally published in <a href="https://levelup.gitconnected.com/">Level Up Coding</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Happy 20th birthday Jira! You suck so bad.]]></title>
            <link>https://medium.com/@ridafkih/happy-20th-birthday-jira-you-suck-so-bad-a731c9958648?source=rss-9c88105465dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/a731c9958648</guid>
            <category><![CDATA[tools]]></category>
            <category><![CDATA[developer-tools]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[management]]></category>
            <category><![CDATA[product-management]]></category>
            <dc:creator><![CDATA[Rida F'kih]]></dc:creator>
            <pubDate>Thu, 06 Oct 2022 06:14:35 GMT</pubDate>
            <atom:updated>2022-10-06T06:14:35.692Z</atom:updated>
            <content:encoded><![CDATA[<p>Jira continues to be an unintuitive, slow displeasure to use, but remains one of the top-picks amongst software management for issue-tracking software.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zsF5mprqPw0NhsrN17IF7g.png" /><figcaption>The world if Jira wasn’t the leading product management platform.</figcaption></figure><h3>What is Jira?</h3><p>For those lucky enough not to know, Jira is the biggest and by far most popular project management and issue tracking tool in and out of the software development space, developed by Atlassian, founded in 2002, and still one of Australia’s biggest international startups.</p><p>Atlassian has created an insanely powerful, customizable tool which boasts robust integrations, every product management feature you could ask for, and yet it seems that it’s often not the case that it’s seen as a piece of software more than it’s seen as a way of life. People live by Jira, and they’ll die by Jira, and I think it just sucks.</p><h3>How does Jira suck?</h3><h4>The Workflow Detriment</h4><p>Jira — as the software that handles my issues in a daily basis — <em>should be</em> the piece of software that I interact with the most on the daily aside from a team communication platform. ie. Discord, Slack, etc.</p><p>However, as much as I want to use Jira in that way, it just can’t be well-integrated into my workflow. It is tucked away into my web-browser, with slow load times combined with convoluted &amp; unintuitive nested navigation to get where I need to go. I <em>should not need</em> to have a special, dedicated “Jira Hole” in my bookmarks to use it effectively.</p><h4>Design Oversight Extravaganza</h4><p>Jira is riddled with what are quite frankly some of the worst design oversights I have seen in any piece of “enterprise ready” software in my life.</p><p>Dare you accidentally hit the wrong key while crafting a lengthy, yet beautifully written text: it shall be sent to the nether never to see again, not a warning in sight. I often find myself in navigation loops, find myself making dead-clicks, or having to click buttons that are not buttons<em> </em>to get where I need to go.</p><p>User experience &amp; user interface design is a very specialized and developed topic in 2022, I’d even consider it a science at this point, and Atlassian has managed to do it so poorly I simply cannot even fathom what is going on behind the scenes. I am a very download-happy person when it comes to trying out new software, and Jira’s user interface has to be the least intuitive, worst-design piece of garbage I have ever had the displeasure of laying my eyes on.</p><p>For software with origins in software development, it baffles me that Jira doesn’t support dark-mode. This means every time I open it, I get flash-banged.</p><h4>Accessibility &amp; Responsiveness</h4><p>Thankfully in 2022, 20-years after it was created, Jira has finally addressed the inability for non-sighted users to use their software, yet it’s still not responsiveness to varying screen sizes. Come on.</p><h4>Context Switching</h4><p>The lack of a native application combined with the unintuitive UI, convoluted navigation, long loading times, content-layout shifts, inscrutable elements, etc., switching to Jira to edit, update, change or comment on a ticket requires a genuine need for context switching. Meaning it’s very common that you’ll lose momentum on tasks with higher cognitive load directly resulting from Jira.</p><p>The cluttered UI alone makes me feel like I’m operating a Boeing 747 in the comfort of my ergonomic chair, all while only having to flip one or two switches and click a button.</p><h4>Performance</h4><p>Working with Jira is like using the controls of military tank to drive a Tuk-Tuk. Complicated yet slow. Fun fact, when you open lightly populated Jira board view, you download ~24MB of data cross ~350 requests, and every ticket you preview is an additional ~20MB across ~90 requests.</p><p>That means if you open the Jira board view, and preview 10 tickets, that’s almost a quarter of a gigabyte that you just downloaded across over 1.25K requests, much of it uncached and redundant.</p><p>If we compare this to Notion with a highly-populated workspace, it initially downloads ~13.5MB over ~120 requests, with each previewed page downloading only about ~0.2MB over ~20 requests.</p><h4>Customization Galore</h4><p>One complaint many others have with Jira is just how customizable it is, management will go absolutely crazy with making Jira a completely new product, implement blocking processes and intense red-tape, and that’s why when someone complains about Jira the catch-all response is either “you’ve configured it wrong,” or “you’re using it wrong.”</p><p>Despite that fact, my experience with Jira has been rather minimalistic, never have I been on a team with overcomplicated processes around Jira itself, nor did we go crazy with the customizations, yet it was still problematic and abrasive to use.</p><h3>Why does Jira suck?</h3><p>Jira promotes bureaucracy-rich workflows that are built to convenience off-the-floor workers, managers, executives, etc., at the expense of those who are interfacing with it on a daily basis. As I outlined in the intro of this post, Jira is an insanely powerful tool, just not for the people who have their sleeves rolled up high. It generates amazing reports, fantastic predictions, fancy charts, great managerial tooling, makes imposing processes easier, has robust integrations, etc., and that’s why most managers I’ve spoken to really enjoy Jira, while on-the-floor engineers either range from fiery-eyed hate to toleration.</p><p>I think Jira does a good job of making teams look much busier than they are, but in the end I see it more as a “talk more not do more” situation.</p><p>A very common response I get when I ask developers why they use Jira is because they either don’t care, or haven’t found a suitable alternative.</p><h3>The Alternative</h3><h4><a href="https://linear.app/">Linear</a></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ch9BQ8dxtewTmrxXsGvDqg.png" /><figcaption>Linear homepage</figcaption></figure><p>Linear is the perfect antithesis of Jira. Rather than a slow, loose, unintuitive ticket management experience, Linear provides a highly fast and intuitive UI with realtime changes wrapped in a beautifully crafted, opinionated platform built with software developers in mind. It cuts out the unnecessary bureaucracy and leaves engineers with a ticket management experience that integrates very well into their day-to-day thanks to its desktop application, theme customizability, command palette, offline functionality, and speed. It integrates into a plethora of software including Zendesk, Intercom, Figma, GitHub, GitLab, Zapier, and gives you full-access to built custom integrations using their GraphQL interface.</p><p>Linear has been a pleasure to use on the teams I’ve worked on that have opted for it, as well as a no-brainer for collaborative personal projects. Although a potential downside to Linear is that it is built explicitly for engineers, thus may not be suitable for other teams such as marketing, design, etc.</p><h4>Other Alternatives</h4><p>If you’ve given Linear a try, but it just doesn’t work for you, some viable alternatives include GitHub Issues, Asana, ClickUp, YouTrack, Trello, Pivotal Tracker, and monday.com.</p><h3>Real Quotes from Jira Users</h3><p>If my article wasn’t enough of an articulation of the common frustrations with Jira, a small directory of quotes exists on a website called <a href="http://ifuckinghatejira.com/">ifuckinghatejira.com</a>, here are a few excerpts.</p><blockquote>Jira is middle-management-ware, a term I made up for software that serves the needs of middle management, or, at least, the needs middle management thinks it has, which comes to the same thing as long as you’re selling to them. What are those needs? Metrics. Being able to make charts and graphs and summarized reports for the next-higher level of management, so they can say that their team is productive.</blockquote><blockquote>Every time I open Confluence or Jira I want to claw my fucking eyes out. It’s slow, hard to navigate, and terrible.</blockquote><blockquote>Tickets in JIRA are not the work itself, never was and never will be, it is a LARP of the work, but it gets taken for the central thing. This is an illusion. Fixing a bug without filing a JIRA ticket is in itself progress. Moving a JIRA card without any other change is not. Yet the second is what’s visible and therefor what’s rewarded.</blockquote><blockquote>I hate Jira. You need to watch a few hours of tutorials to be able to understand this piece of crap.</blockquote><blockquote>The momentum of its user base plus incoherent analyst opinions only serve to discourage moving to something actually useful/modern/user centered/updated/etc.</blockquote><blockquote>It is bad, really bad, like come on your page takes 5 seconds to load on every click with a 100Mb internet and loads of ram, seriously? I don’t want to talk about the super unintuitive interface. It is basically cancer. And you can’t use something else if your organisation decides to use it.</blockquote><blockquote>it’s not meant for devs but for project managers — and project managers like to make the devs do their job in that horrific tool. Imo there should be a dev view that is dead simple, and a PM view with all the complicated bells and whistles.</blockquote><blockquote>Even stripped down, it’s still too complicated. The wealth of features tend to lead to practices that can be bad for overall productivity even if they look useful on the surface.</blockquote><blockquote>JIRA is powerful. BUT… the UX is bloody awful. As in makes me want to stab myself in the eyes daily. The number of times I’ve lost content due to terrible and buggy UI is growing numerous.</blockquote><blockquote>JIRA. Fucking JIRA. Everybody just fucking hates it. It tops the list of shit pieces of software by a fair margin, followed by JIRA in second place and JIRA in 3rd.</blockquote><blockquote>Jira presents an excellent exercise on how not to do UX. The interface is slow, cluttered and unresponsive. Want to figure out how to do anything? God help you, because the design certainly won’t.</blockquote><blockquote>I avoid doing any kind of work with JIRA besides what’s absolutely necessary — and even then I pull my hair out in frustration.</blockquote><blockquote>Jira is so mind bogglingly awful, clunky and slow, I would rather peel off my skin and bathe my weeping raw flesh in a bath of vinegar than have to use Jira for one more day!</blockquote><p>You can find more quotes like these are ifuckinghatejira.com, it’s a little cathartic, honestly.</p><p>You can read this blog post, and more like it on my <a href="https://rida.dev/">personal website.</a> Want to argue with me about how much you love Jira and disagree with my opinion? <a href="https://twitter.com/ridafkih/">Tweet me @ridafkih on Twitter!</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a731c9958648" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Maintaining TypeScript Superpowers When Types Are Out of Reach]]></title>
            <link>https://medium.com/@ridafkih/maintaining-typescript-superpowers-when-types-are-out-of-reach-ab3357d2ea4e?source=rss-9c88105465dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/ab3357d2ea4e</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[typescript]]></category>
            <dc:creator><![CDATA[Rida F'kih]]></dc:creator>
            <pubDate>Wed, 13 Apr 2022 15:23:57 GMT</pubDate>
            <atom:updated>2022-04-13T15:25:59.182Z</atom:updated>
            <content:encoded><![CDATA[<h4>Working with TypeScript when libraries don’t export types, or types are never explicitly defined or named.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ph_RcyVQ4F8MymSrIdkkxg.png" /><figcaption>TypeScript is super, but can be a little less intuitive than other type-safe languages.</figcaption></figure><p>It’s all too common. You’re coding away in TypeScript, utilizing an external library, and you’re digging around the code for that type you just can’t find and… bam! The type you’ve been searching for is not exported!</p><p>You could either re-create the types locally, fork the repository and export the types, or <strong>work with what you’ve got!</strong> Today, I’m going to show you how to do the latter.</p><h3>Inferred Return Types</h3><p>Let’s say we’re utilizing a function from an external library which returns an object that lacks explicitly defined type information as follows.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/46110699b80c771ebf96607a4ce9c20f/href">https://medium.com/media/46110699b80c771ebf96607a4ce9c20f/href</a></iframe><p>When using this function, TypeScript will automatically infer the type as follows.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d11834091df075ddbe2b6cec423298c0/href">https://medium.com/media/d11834091df075ddbe2b6cec423298c0/href</a></iframe><p>This is fine for basic usage, but if we want to do something with the type, it may become difficult.</p><p>If you’re unfamiliar with the ReturnType, your first instinct might be to recreate the type yourself.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/925928de9a61c15fd54bc1c445b3fa03/href">https://medium.com/media/925928de9a61c15fd54bc1c445b3fa03/href</a></iframe><p>Thanks to ReturnType, which takes a generic — that being a function type signature — we can get the return type even if its not explicitly named.</p><p>We can either use it directly, or assign it to our own named type.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fa1629942c92f908980cf65b07d1498e/href">https://medium.com/media/fa1629942c92f908980cf65b07d1498e/href</a></iframe><p>Now we are able to use this as a property in another local function.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d0b35abeb10fc74f839014eb6a98f0da/href">https://medium.com/media/d0b35abeb10fc74f839014eb6a98f0da/href</a></iframe><p>🎉 Awesome! This is so much better!</p><h3>Nested, Unnamed Types</h3><p>Sometimes we do have an exported type, but we just want one property of that type. Again, if you’re unfamiliar with TypeScript your first instinct might be to simply redeclare the type. However, we can actually access that by simply using our handy square brackets.</p><p>Let’s say we have the following interface.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a5ca6089a4f32e9b8e91d6680f919191/href">https://medium.com/media/a5ca6089a4f32e9b8e91d6680f919191/href</a></iframe><p>Now let’s say we want to create a function that checks if a human being’s language is English, but we only want to pass in the language name in a type-safe manner, rather than passing in the whole human.</p><p>All we do is narrow the type down the interface using the keys inside some square brackets, and we’ve got a type safe function!</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1459cc10b566642700bad046382c93c0/href">https://medium.com/media/1459cc10b566642700bad046382c93c0/href</a></iframe><p>✨ Easy peasy, right?</p><h3>Variable Unnamed Object Type Signatures</h3><p>This one is a little more obscure, but something I ran into while creating a custom Notion renderer for <a href="https://rida.dev/">the latest version of my personal portfolio</a>. If we have an array where we have multiple possible type signatures of objects, and the possible object types in question are not named, things can get yucky very quickly.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3be7975d96d320a0ca5f7bd880fcc150/href">https://medium.com/media/3be7975d96d320a0ca5f7bd880fcc150/href</a></iframe><p>As you can see, the attributes are inconsistent.</p><p>Let’s define an array of objects which utilizes our CustomHTMLElement type.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/be02ac622ae4ff6742c57d04776a58fa/href">https://medium.com/media/be02ac622ae4ff6742c57d04776a58fa/href</a></iframe><p>Let’s say we want to get a list of all the img elements, our first instinct might be to use the raw Array#filter method.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/07d6ae77a738784192f7aa0f10a0ad6e/href">https://medium.com/media/07d6ae77a738784192f7aa0f10a0ad6e/href</a></iframe><p>As you can see, the problem with this is Array#filter does not immediately respect type inferences. TypeScript still has no idea that any of the other object types have been eliminated as a possibility.</p><p>In this case, the inferred type of the return type of the getAllImgElements function is () =&gt; CustomHTMLElement[], so we still have the exact same original degree of ambiguity.</p><p>Thankfully, we can leverage the Extract generic type available in TypeScript 2.8+ combined with a TypeScript predicate to tell TypeScript what to expect after we’ve filtered.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/80a82d5fe43769fd89473165d1d4d7b9/href">https://medium.com/media/80a82d5fe43769fd89473165d1d4d7b9/href</a></iframe><h3>Conclusion</h3><p>TypeScript is an absolute beast, but because of the nature of its subset language: JavaScript, things can get a little funky sometimes. Luckily, we all love a challenge.</p><p>You can read more content like this on <a href="https://rida.dev/">my personal blog!</a></p><p>If you liked this post, check me out <a href="https://twitter.com/ridafkih">on Twitter</a> to be kept up to date on future posts! ❤️</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ab3357d2ea4e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Not Expose the Personal Data of 19,577 Canadians]]></title>
            <link>https://medium.com/@ridafkih/how-to-not-expose-the-personal-data-of-19-577-canadians-985669c9c1d9?source=rss-9c88105465dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/985669c9c1d9</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Rida F'kih]]></dc:creator>
            <pubDate>Tue, 12 Apr 2022 07:28:21 GMT</pubDate>
            <atom:updated>2022-04-12T07:44:53.773Z</atom:updated>
            <content:encoded><![CDATA[<h4>PORTpass is a prime example of poorly handling private user data, let’s explore and learn from the oversights in their security measures.</h4><p>A few months ago I spoke with <a href="https://www.cbc.ca/news/canada/calgary/portpass-app-proof-of-vaccination-unsecured-data-update-1.6229034">CBC news</a> to give an overview of a plethora of security flaws I found in PORTpass, an attempt to bring digital proof-of-vaccine to Canadians. While that article was meant for a broader audience, today I will outline their security flaws from a technical perspective for all the developers out there.</p><h3><strong>My Background</strong></h3><p>My name is Rida F’kih, I am a 21 year old Canadian software developer &amp; reverse engineer at <a href="https://maxrewards.com/">MaxRewards.</a></p><p>My development journey started at 15, from reverse-engineering to scammer-vigilantism then teaching coding to kids to web &amp; mobile development.</p><h3><strong>What was PORTpass?</strong></h3><p>PORTpass was a private attempt by a local Calgarian entrepreneur to bring vaccine passports to Canadians.</p><h3>The Data At Risk</h3><p>The data at risk wasn’t light stuff.</p><p>PORTpass had the business requirement of collecting loads of personal data, collecting photos of government IDs, health card numbers, verification selfies, full names, dates of births, blood types, and more.</p><p>The data on PORTpass would be enough to be at risk of social engineering, or even have financial accounts opened in your name.</p><h3><strong>What went wrong?</strong></h3><p>First, we must familiarize ourselves with Murphy’s Law.</p><blockquote><em>Murphy’s law is an adage or epigram that is typically stated as: “Anything that can go wrong will go wrong.”</em></blockquote><blockquote><a href="https://en.wikipedia.org/wiki/Murphy%27s_law"><em>— Wikipedia, Murphy’s Law</em></a></blockquote><p>I’d argue that PORTpass was the epitome of Murphy’s Law from the perspective of the user, and criminal negligence on behalf of its creator due to their inaction after these issues were brought to light.</p><h3><strong>The Vulnerability</strong></h3><p>The primary vulnerability is called “Improper Access Control,” which is described by the <a href="https://cwe.mitre.org/">Common Weakness Enumeration</a> — a community-developed list of software &amp; hardware weakness types — as “software [that] does not restrict or incorrectly restricts access to a resource from what should be an unauthorized actor.”</p><p>Some pseudo-code to describe a properly managed &amp; created endpoint may appear as follows.</p><pre>import express from &quot;express&quot;;<br>import { loggedInUser } from &quot;@/utils/authentication&quot;;<br>import { getUserInfo } from &quot;@/utils/users&quot;;</pre><pre>const app = express();</pre><pre>app.get(&quot;/user/:userId&quot;, (request, response) =&gt; {<br>  const { userId } = request.params;<br>  const authenticatedUserId = loggedInUser(request);<br><br>   if (!authenticatedUserId  || authenticatedUserId !== userId)<br>     return response.status(401).send(&quot;Unauthorized&quot;);<br>   else<br>     return response.status(200).json(getUserInfo(userId));<br>});</pre><p>Here, we would send a GET request to /user/[userId], and receive back user data only if we are authenticated into the same user we are requesting.</p><p>A poorly architected endpoint may be coded as follows.</p><pre>app.get(&quot;/user/:userId&quot;, (request, response) =&gt; {<br> const { userId } = request.params;</pre><pre> if (!loggedInUser(request))<br>  response.status(401).send(&quot;Unauthorized&quot;);<br> else<br>  response.status(200).json(getUserInfo(userId));<br>});</pre><p>Here, we’re not checking <strong>which user</strong> is authenticated, only <strong>if </strong>the user is authenticated. Thus, an authenticated user could request ANY resource, even if it doesn’t belong to them. For public posts this is appropriate, for private information like government-issued photo IDs, health care cards, and confirmation portraits, this is a massive flaw.</p><h3><strong>The Catalysts</strong></h3><p><strong>Sequential User IDs</strong></p><p>PORTpass users requested their resource by using sequential user IDs. This means that if you were the first user to sign up for their service, your ID would be 1, if you were the second, it would be 2, etc.</p><p>Had they used a cryptographic solution — such as UUIDv4 — scraping user information would have been significantly more difficult, however in this case formulating a script to collect all registered user data was trivial.</p><pre>/**<br> * Gets the user profile from the PortPass API.<br> * <a href="http://twitter.com/param">@param</a> {number|string} userId The user ID of the target user.<br> * <a href="http://twitter.com/returns">@returns</a> {Promise&lt;any&gt;} A user object.<br> */<br>const getUserProfile = async (userId) =&gt; {<br>  const profile = await axios<br>    .get(USER_PROFILE_URI + userId.toString())<br>    .then((response) =&gt; response?.data)<br>    .catch(() =&gt; ({}));</pre><pre>  return profile;<br>};</pre><pre>for (let i = 0; i &lt; 19577; i++)<br>  getUserProfile(i + 1).then(saveUserData);</pre><p><strong>No SSL</strong></p><p>Since PORTpass didn’t have SSL certificates, packets that your device sends or receives could be altered or intercepted. With websites, its easy to identify a secure website by finding the little “lock icon” next to the URL, however with applications its a little more ambiguous.</p><p><strong>Exposing Developer Tooling</strong></p><p>PORTpass’ backend was created using Django, which has an interface which allows you to test endpoints from your browser without having to use REST tooling like Postman, or Insomnia. Optimally, PORTpass would have secured their endpoints so knowing their paths would provide no additional capabilities, however, they didn’t, and thus traversing their entire backend was trivial.</p><h3>Conclusion</h3><p>We all want to get our projects out there, but if we don’t have the experience necessary to accommodate for basic security considerations, getting your code reviewed or learning the basics of security should be considered good options.</p><p>In this case, a non-technical founder wanted to hastily get a product out there, so they hired a developer from overseas without the ability to evaluate the quality of code.</p><p>I’m very thankful to the CBC for their help in finally being able to hold the creator of PORTpass accountable, an address these concerns rather than simply ignoring them or claiming to be defamed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*OshuX1hFhTvXpSf0i8kNVw.gif" /><figcaption>Bart Simpson displays the same reaction I did.</figcaption></figure><p>Did you enjoy this content? You can read more posts like this by visiting my <a href="https://rida.dev/">personal portfolio</a>, and you can <a href="https://twitter.com/ridafkih?ref_src=twsrc%5Etfw">follow me on Twitter</a> to get updates when I create new articles.</p><p><a href="https://www.rida.dev/blog/how-to-not-expose-the-personal-data-of-19-577-canadians-570451a57fd044afb694d5b3fb6fbdd0">Click here to read this post on my blog.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=985669c9c1d9" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>