Jailbreak detection with jail-monkey on React Native app

Mobile device operating systems often impose certain restrictions to what capabilities the user have on the device like which apps can be installed on the device and what access to information and data apps and user have on the device. The limitations can be bypassed with jailbreaking or rooting the device which might introduce security risks to your app running on the device so you might want to detect if your app is run on jailbroken device.

Jailbreak detection

Detecting and possible acting regarding the device status can be beneficial depending on your app features. The reason for detection is to either disable some, or most of the app's functionalities due to security concerns that come from a jailbroken system. You might want to e.g. prevent jailbroken devices from authenticating to protected applications. There are different methods to use and one of the easiest is to use libraries like jail-monkey.

Overall the jailbreak detection is based on several different aspects on the device which: file existence checks, URI scheme registration checks, sandbox behavior checks, abnormal services and dynamic linker inspection.

jail-monkey is a React Native library for detection if a phone has been jail-broken or rooted for iOS and Android. (note: the library is not actively maintained)

Are users claiming they are crossing the globe in seconds and collecting all the Pokeballs? Some apps need to protect themselves in order to protect data integrity. JailMonkey allows you to:

  • Identify if a phone has been jail-broken or rooted for iOS/Android.
  • Detect mocked locations for phones set in "developer mode".
jail-monkey

Using jail-monkey is straightforward and after adding the library to your app the only unanswered question is what you want to do with the information. Do you block the app from running, limit some features or just log the information to e.g. Sentry or some analytics platform.

import JailMonkey from 'jail-monkey'

if (JailMonkey.isJailBroken()) {
  // Alternative behaviour for jail-broken/rooted devices.
}

jail-monkey answers to following questions:

  • can the location be mocked?
  • is the device in debug mode?
  • is the device jailbroken?
  • on iOS the reason for jailbroken
  • on Android: i.a. adb enabled, development settings mode

You show the jailbreaking status for example as a banner in the app:

Jailbreak detected!

Is it worth it?

Implementing jailbreak detection is easy but you might want to consider if it brings anything of value. Jailbreaking an iOS device does not, on its own, make it less secure but it makes harder to reason about the security properties of the device and more concerning issue is that users of jailbroken devices frequently hold off on updating their devices, as jailbreak development usually lags behind official software releases.

Jailbreak / root detection is never perfect and more or less hinders only the less technology savvy users and these kinds of checks don't contribute too much to the security side. Also it can result in false positives as jail-monkey's issue tracker shows. Hackers are usually one step ahead than detection mechanisms so relying on the jailbreaking status should be taking with a grain of salt.

Bypassing different jailbreak detection secure mechanisms is just a matter of effort as the guide for bypassing jail-monkey and jailbreak detection bypass articles show. There's also ready made tools for iOS like iHide. So if you seriously plan to detect and secure your app against jailbreaking you should implement your own tools or use some custom made library.

If you want to read more about jailbreak detection Duo has written a good analysis of jailbreak detection methods and the tools used to evade them.

Running Detox end-to-end tests on CI

Now that you've added end-to-end tests with Detox to your React Native application from my previous blog post it's time to automate running the tests and add them to continuous integration (CI) pipeline. Detox has documentation for running it on some Continuous Integration services but it's somewhat lacking and outdated. This post will show how to automate E2E testing on GitHub Actions.

Detox E2E tests on GitHub Actions

GitHub Actions makes it easy to automate software workflows and basically provides some capabilities than any common CI/CD service like GitLab, CircleCI, Bitrise etc. At work I used GitLab CI/CD to run our e2e tests so adding automation for my personal Hailakka project on GitHub Actions was a nice exercise. You can see the workflow file from the repository: ios.yml

Creating the workflow for GitHub Actions was quite straightforward by modernizing the workflow shown in the article I found and there's more modern blog post also which covers also Azure Pipelines.

GitHub Actions provides a macOS runner so setting up things were as simple as writing the steps you'd do manually for running the Detox tests and translating those steps to workflow. Adding a workflow for iOS and getting tests to run was easy. The result was simple pipeline on repository "push" action in pull request and master branches.

GitHub Actions workflows

There is a workflow for Hailakka on Android but I managed it to get running only on API level 29 (or lower) on the GitHub Actions although locally it run on API level 31. Somehow the newer API didn't create any UI (empty images) for Detox to click through. Anyways the Android tests seemed more flaky even when running on local machine.

Detox tests for my simple newsreader application runs on iOS runner quickly after the app was build. The total runtime for the workflow run is around 30 minutes. As I've set the artifacts to be generated only when the tests fail the output is just a succeeded job. Maybe I should look into partial visual regression testing 🤔

Detox tests on GitHub Actions job

You can add a badge to your readme of the workflow status ✅

Workflow run for iOS passes

Automated End-to-End testing React Native apps with Detox

Everyone knows the importance of testing in software development projects so lets jump directly to the topic of how to use Detox for end-to-end testing React Native applications. It's similar to how you would do end-to-end testing React applications with Cypress like I wrote previously. Testing React Native applications needs a bit more setup especially when running on CI/CD but the benefits of having comprehensive tests is great. This article focuses on using Detox and leaves the setup stuff for the official documentation.

Detox for end-to-end testing

End-to-end testing is widely performed in the web applications using frameworks like Cypress but with mobile applications it's not as common. There are essentially couple of frameworks for end-to-end testing mobile applications: Detox and Appium.

This article covers how to use Detox which uses grey-box-testing by monitoring the state of the app to tackle the problem of flaky tests. The main difference between Appium and Detox is that Appium uses black-box-testing, meaning that it doesn't monitor the internal state of the app. There's a good article of comparing Detox and Appium with example projects.

I'll use my personal Hailakka project as an example of setting up Detox for end-to-end testing and for visual regression testing. The app is based on my native Highkara news reader but done in React Native and is still missing features like localization.

Hailakka on Android and iOS

Setup Detox for React Native project

Starting with Detox e2e and React Native gets you through setting Detox up in your project, one step at a time both for Android and iOS.

Detox provides an example project for React Native which shows a starting point for your own e2e tests. It's good to note that support for Mocha is dropped on upcoming Detox 20.

Now you just need to write simple e2e tests for starters and build your app and run Detox tests. Detox has good documentation to get you through the steps and has some troubleshooting tips you might come across especially with Android.

Detox with Expo

Using Detox with Expo projects should work quite nicely without any helper libraries (although some older blog posts suggests so). You can even run e2e tests on EAS builds. For practice I added example of using Detox to my personal Hailakka project with managed workflow.

The changes compared to non-Expo project I followed the Detox on EAS build documentation and added the @config-plugins/detox for a managed project. Also to get the native projects for Detox I ran the npx expo prebuild script which practically configured both iOS and especially Android projects to work with Detox!. You can see my detox.config.js from my GitHub.

Running Detox end-to-end tests

With iOS related tests on simulator I got everything working pretty smoothly but on Android I had some problems to troubleshoot with the help of Detox documentation. Using the FORCE_BUNDLING=true environment variable helped to get rid of the Metro bundler when running Detox as Android emulator had problems connecting to it. Before that I got "unable to load script from assets index.android.bundle" error and I had to use adb reverse tcp:8081 tcp:8081 for proxying the connection.

For running the Detox tests I created the following npm scripts.

"e2e:ios": "npm run e2e:ios:build && npm run e2e:ios:run",
"e2e:ios:build": "detox build --configuration ios.development",
"e2e:ios:run": "detox test --configuration ios.development",
"e2e:android": "npm run e2e:android:build && npm run e2e:android:run",
"e2e:android:build": "detox build --configuration android.development",
"e2e:android:run": "detox test --configuration android.development",

Note on running on Android: Use system images without Google services (AOSP emulators). Detox "strongly recommend to strictly use this flavor of emulators for running automation/Detox tests.".

Also remember to change the Java SDK to 11. You can do it with e.g. asdf.

brew reinstall asdf
asdf plugin add java
asdf list-all java
asdf install java zulu-11.60.19
asdf global java zulu-11.60.19

If you need to debug your Detox tests on Android and run Metro bundler on the side you might need to start the metro builder (react-native start) manually. Also when using concurrently the arguments need to be passed through to desired script, e.g. "e2e:android:run": "concurrently --passthrough-arguments 'npx react-native start' 'npm run e2e:android:test -- {@}' --",.

Running same tests on iOS and Android have some differences and it helps to use "--loglevel=verbose" parameter to debug component hierarchy. For example opening the sidebar navigation from icon button failed on Android but worked on iOS. The issue was that I was using Android system image with Google's services and not the AOSP version.

Setting locale for Detox tests

Detox provides launchApp command which allows you to accept permissions and set language and locale.

For example in beforeAll you can set the locale for and accept the permissions for notifications as we can't accept it when the app runs and the modal is shown.

beforeAll(async () => {
    await device.launchApp({
        languageAndLocale: { language: 'en', locale: 'en-US' },
        newInstance: true,
        permissions: { notifications: 'YES' }, // This will cause the app to terminate before permissions are applied.
    });
});

But unfortunately setting the languageAndLocale works only on iOS. For Android you need a lot more steps to achieve that. Fortunately I'm not alone and "Changing Android 10 or higher device Locale programatically" covers just what I needed. You can use the Appium Settings application and get it to automatically installed to the emulator by using "utilBinaryPaths" as shown in Detox documentation

You can run the needed adb shell commands with execSync when setting up the tests:

import { execSync } from 'child_process';

// Set permissions for Settings app for changing locale
execSync('adb shell pm grant io.appium.settings android.permission.CHANGE_CONFIGURATION');
// Set lang and country
execSync(`adb shell am broadcast -a io.appium.settings.locale -n io.appium.settings/.receivers.LocaleSettingReceiver --es lang fi --es country FI`

Tips for writing Detox tests

People at Siili have written about Detox testing native mobile apps which provides good practices for testing.

  • Start each scenario from a predictable application state. Using beforeAll, beforeEach, await device.reloadReactNative() methods can help with that
  • Add testIDs to the elements you are going to use in the tests,
  • Keep all locators in one place (changing them in the future will not cost too much time)
  • Create helpers method to make your code more legible and easily maintainable

Visual regression testing React Native apps with Detox

Now we have achieved end-to-end tests with Detox but we can do more. By harnessing Detox for visual regression testing we can "verify the proper visual structure and layout of elements appearing on the device's screen". Detox supports taking screenshots, which can be used for visual regression testing purposes as they describe in their documentation.

  • Taking a screenshot, once, and manually verifying it, visually.
  • Storing it as an e2e-test asset (i.e. the snapshot).
  • Using it as the point-of-reference for comparison against screenshots taken in consequent tests, from that point on.

They write that "more practical way of doing this, is by utilizing more advanced 3rd-party image snapshotting & comparison tools such as Applitools." And here is were we come into the good article of how to do Visual regression testing with Detox. In short, we use Jest Image Snapshot and recommendations using SSIM Comparison.

jest-image-snapshot generates an image which shows thee baseline and how it differs with current state with red color.

jest-image-snapshot baseline diff with Detox

To aid writing tests, use some convenience methods by extending Jest expect and automatically taking a screenshot if the method is invoked; consider the platform and device name when doing the comparisons.

Helper methods in setup.ts extending Jest expect, adapted to TypeScript from Visual regression testing React Native apps with Detox and Jest:

import { device } from 'detox';
import fs from 'fs';
import { configureToMatchImageSnapshot } from 'jest-image-snapshot';
import path from 'path';
const jestExpect = (global as any).expect;

const kebabCase = (str: string) =>
    str.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)!.join('-').toLowerCase();

const toMatchImage = configureToMatchImageSnapshot({
    comparisonMethod: 'ssim',
    failureThreshold: 0.01, // fail if there is more than a 1% difference
    failureThresholdType: 'percent',
});

jestExpect.extend({ toMatchImage });

jestExpect.extend({
    async toMatchImageSnapshot(
        // a matcher is a method, it has access to Jest context on `this`
        this: jest.MatcherContext,
        screenName: string
    ) {
        const { name } = device;
        const deviceName = name.split(' ').slice(1).join('').replace('(','').replace(')', '');
        const language = languageAndLocale();
        const SNAPSHOTS_DIR = `__image_snapshots__/${language.code}/${deviceName}`;
        const { testPath } = this;
        const customSnapshotsDir = path.join(path.dirname(testPath || ''),
SNAPSHOTS_DIR);
        const customSnapshotIdentifier = kebabCase(`${screenName}`);
        const tempPath = await device.takeScreenshot(screenName);
        const image = fs.readFileSync(tempPath);
        jestExpect(image).toMatchImage({ customSnapshotIdentifier, customSnapshotsDir });
        return { message: () => 'screenshot matches', pass: true };
    },
});

Writing an expectation for an image comparison then becomes as simple as (HomeScreen.e2e.ts):

import { by, element, expect } from 'detox';

const jestExpect = (global as any).expect;

describe('Home Screen', () => {
  it('should show section header', async () => {
    await expect(element(by.id('navigation-container-view'))).toBeVisible();

    await jestExpect('Home Screen').toMatchImageSnapshot();
  });
});

You should also put the device into demo mode by freezing the irrelevant, volatile elements (like time, network information etc.). The helper.ts might look like:

import { execSync } from 'child_process';
import { device } from 'detox';

export const setDemoMode = async () => {
    if (device.getPlatform() === 'ios') {
        await (device as any).setStatusBar({
            batteryLevel: '100',
            batteryState: 'charged',
            cellularBars: '4',
            cellularMode: 'active',
            dataNetwork: 'wifi',
            time: '9:42',
            wifiBars: '3',
        });
    } else {
        // enter demo mode
        execSync('adb shell settings put global sysui_demo_allowed 1');
        // display time 12:00
        execSync('adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1200');
        // Display full mobile data with 4g type and no wifi
        execSync(
            'adb shell am broadcast -a com.android.systemui.demo -e command network -e mobile show -e level 4 -e datatype 4g -e wifi true'
        );
        // Hide notifications
        execSync('adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false');
        // Show full battery but not in charging state
        execSync(
            'adb shell am broadcast -a com.android.systemui.demo -e command battery -e plugged false -e level 100'
        );
    }
};

And as your application changes you may want to add some script to update the snapshots to you package.json

"e2e:ios:refresh": "npm run e2e:ios:build && npm run e2e:ios:run -- --updateSnapshot",
"e2e:android:refresh": "npm run e2e:android:build && npm run e2e:android:run -- --updateSnapshot",

Now you can just enjoy your end-to-end tests taking care that the application looks and works like you want it to after changes. And wait for React Native Owl to mature for getting out-of-the box visual regression testing.

The visual regression testing part of using Detox was for my case more of a theoretical practice than a real use case. As the visual regression testing compares current state to baseline images but with my personal is news reader with changing news it isn't feasible at it's current state.

Notes from React Native EU 2022

React Native EU 2022 was held couple of weeks ago and it's a conference which focuses exclusively on React Native but consists also on general topics which are universal in software development while applied to RN context. This year the online event provided great talks and especially there were many presentations about apps performance improvements, achieving better code and identifying bugs. Here are my notes from the talks I found interesting. All of the talks are available in conference stream on Youtube.

Better performance and quality code from RN EU 2022

This year the React Native EU talks had among other presentations two common topics: performance and code quality. Important aspects of software development which are often dismissed until problems arise so it was refreshing to see it talked so much about.

Here are my notes from the talks I found most interesting. Also the "Can't touch this" talk about accessibility was a good reminder that not everyone use their mobile devices by hand.

How we made our app 80% faster, a data structure story

Marin Godechot gave an interesting talk of React Native apps performance improvements and one of the crucial tools for achieving that.

Validate your assumption before investing in solutions

The learnings of the talk which went through trying different approaches to fix the performance problem was that:

  • Validate your assumption before investing in solutions
  • Performance improvements without tooling is a guessing game
  • Slow Redux selectors are bad
  • Data structures and complexity matters

The breakthrough for finding the problem was after actually measuring the performance with Datadog Real User Monitoring (RUM) and better understanding of the bottlenecks. What you can't measure, you can't improve.

The issue wasn't with useless rerenders, lists and navigation stack but with the datamodels but not the one you would guess. Although the persisted JSON stringified state with Redux was transferred between the JS side and the Native (JS <-> json <-> Bridge <-> json <-> Native) it wasn't the issue.

The big reveal was that when they instrumented Redux's selectors, reducers and sagas to monitoring tool they found that as the user permissions were handled by using the Attribute Based Access Control model the data in JSON format had grown over the years from 15 permissions per user to 10000 permissions per user which caused problems with Redux selectors. The fix was relatively simple: change array to object -> {agengy: [agency:caregivers:manage]}

What you can't measure, you can't improve

You can go EVERYWHERE but I can go FAST - holistic case study on performance

Jakub Binda made a clever comparison in his talk that apps are like cars and same modifications apply to fast cars and fast applications.

The talk starts slow but gets to speed nicely with good overview how to create faster apps. Some of the points were:

  • Reduce weight:
    • Remove dead / legacy code
    • Avoid bundling heavy JSON files (e.g. translations)
    • Keep node_modules clean
  • Keep component structure "simple"
    • More complex structure leads to longer render time and more resources consumption and more re-renders
    • Shimmers are complex and heavy (improve UX by making an impression that content appers faster than it actually does)
  • Using hooks:
    • Might lead to unexpected re-renders when: their value change, dependency array is not set correctly
    • Lead to increased resources comsumption if: their logic is complex, the consumer of the results is hidden behind the flag
  • Tooling:
    • Flipper debug tool: flame charts & performance monitoring tooling

Reducing bugs in a React codebase

Darshita Chaturvedi's hands-on and thoroughly explained talk for identifying bugs in React codebase was insightful.

Reducing bugs in a React codebase

Getting Better All the Time: How to Escape Bad Code

Josh Justice had a great presentation with hands-on example of an application with needed fixes and features and how to apply them with refactoring. And what is TDD by recreating the application.

The slides are available with rest of the TDD sequence and pointers to more resources on TDD in RN.

Refactoring

The key point of the talk was about what do you do about bad code? Do you work around bad code or rewrite bad code? The answer is refactoring: small changes that improve the arrangements of the code without changing its functionality. And comprehensive tests will save you with refactoring. The value is that you're making the improvements that pay off right away and code is shippable after each refactoring. But how do you get there? By using Test-Driven Development (TDD)

"TDD is too much work"
Living with bad code forever is also a lot of work

Getting Better All the Time: How to Escape Bad Code

"Make code better all the time (with refactoring and better test coverage)"

Visual Regression Testing in React Native

Rob Walker talked about visual regression testing and about using React Native OWL. Slides available.

React Native OWL:

  • Visual regression testing for React Native
  • CLI to build and run
  • Jest matcher
  • Interaction API
  • Report generator
  • Inspired by Detox
Baseline, latest, diff
Easy to approach (in theory)

Different test types:

  • Manual testing pros: great for exploratory testing, very flexible, can be outsourced
  • Manual testing cons: easy to miss things, time consuming, hard to catch small changes
  • Jest snapshot tests pros: fast to implement, fast to run, runs on CI
  • Jest snapshot tests cons: only tests in isolation, does not test flow, only comparing JSX
  • Visual regression tests pros: tests entire UI, checks multi-step flows, runs on CI
  • Visual regression tests cons: can be difficult to setup, slower to run, potentially flaky
Use case for visual regression tests

Can't touch this - different ways users interact with their mobile devices

Eevis talked about accessibility and what does this mean for a developer. The slides give a good overview to the topic.

  • Methods talked about
    • Screen reader: trouble seeing or understanding screen, speech or braille feedback, voiceover, talkback
    • Physical keyboard: i.a. tremors
    • Switch devices: movement limiting disabilites
    • Voice recognition
    • Zooming / screen magnifying: low vision
  • 4 easy to start with tips
    • Use visible focus styles
    • Annotate headings (accessibilityRole)
    • Add name, role and state for custom elements
    • Respect reduced motion
  • Key takeaways
    • Users use mobile devices differently
    • Test with different input methods
    • Educate yourself
4 easy to start with tips

Performance issues - the usual suspects

Alexande Moureaux hands-on presentation of how to use Flipper React DevTools profiler and Flamegraph and Android performance profiler to debug Android application performance issues. E.g. why the app has below 60 fps? Concentrates on debugging Android but similar approaches work also for iOS.

First make your measures deterministic, average your measures over several iterations, keep the same conditions for every measure and automate the behavior you want to test.

The presentation showed how to use Flipper React DevTools profiler Flamegraph to find which component is slow and causes e.g. rerendering. Then refactoring the view by moving and the updating component which caused rerendering. And using @perf-profiler/web-reporter to visualize the measures from JSON files.

You can record the trace Hermes profiler and open it on Google Chrome:

  • bundleInDebug: true
  • Start profiler in simulator, trace is saved in device
  • npx react-native profile-hermes pulls the trace and converts it for usable format
  • Findings: filtering tweets list by parsing weekday from tweet was slow (high complexity), replace it with Date.getDay from tweet.createdAt

Connect the app to Android Studio for profiling: finding long running animation (background skeleton content "grey boxes")

How to actually improve the performance of a RN App?

Michal Chudziak presented how to use Define, Measure, Analyze, Improve, Control (DMAIC) pattern to improve performance of a React Native application.

  • Define where we want to go, listen to customers
  • Make it measurable
  • Analyze common user paths
  • Choose priorities

Define your goals:

Define

Measure: where are we?

  • React Profiler API
  • react-native-performance
  • Native IDEs
  • Screen capture
  • Flipper & perf monitor
Measure

Measureme

  • Measurement needs to be accurate and precise

Analyze phase: how do we get there?

  • List potential root causes
  • Cause and effect diagram (fish bone diagram)
  • Narrow the list
Analyze

Improve phase

  • Identify potential solutions
  • Select the best solution
  • Implement and test the solution
Improve

Control phase: are we on track?

Performance will degrade if it's not under control so create a control plan.

Control

Monitor regressions

  • Reassure: performance regression testing (local + CI)
  • Firebase: performance monitoring on production
  • Sentry:  performance monitoring on production

Raspberry Pi 3+ and Joy-IT 7" touchscreen on Debian 11

I've had for sometime a Joy-IT 7" IPS display for Raspberry Pi waiting in my drawer and now I got around to put it into use with Ikea Ribba frame. Setting up the touch screen was easy but getting it inverted (upside down) took some extra steps.

The touchscreen is "RB-LCD-7-2" from Joy-IT which is a 7" IPS display for Raspberry Pi with 1024x600 resolution and 5 point capacitive touchscreen and HDMI connector. The manufacturer provides a manual for setting it up but as things have changed during the years it didn't work out of the box for the inverted touch matrix.

I installed Debian GNU/Linux 11 (bullseye) to my Raspberry Pi Model 3 plus and did the following changes:

Display working

Edit /boot/config.txt

max_usb_current=1
hdmi_force_hotplug=1
# or 4
config_hdmi_boost=7
hdmi_group=2
hdmi_mode=1
hdmi_mode=87
# or 1
hdmi_drive=2
display_rotate=2
hdmi_cvt 1024 600 60 6 0 0 0

Inverted display

Flip the command line by editing /boot/cmdline.txt and adding

fbcon=rotate:2

For inverting the GUI use evdev:

sudo apt-get install xserver-xorg-input-evdev
sudo mv /usr/share/X11/xorg.conf.d/10-evdev.conf

/usr/share/X11/xorg.conf.d/45-evdev.conf

Section "InputClass"
        Identifier "evdev touchscreen catchall"
        MatchIsTouchscreen "on"
        MatchDevicePath "/dev/input/event*"
        Driver "evdev"
        Option "InvertX" "true"
        Option "InvertY" "true"
EndSection

Resources:

Short notes on tech 31/2022

Software development

How to explain technical architecture with a natty little video
Some thoughts on explaining architecture through diagraming, in particular the advantage of scrappy videos to show diagramming step-by-step. (from DevOps Weekly)

What Are Vanity Metrics and How to Stop Using Them
Measurement and metrics are an important part of devops practices, but establishing metrics always risks issues with vanity metrics. This post explains what they are and how to avoid them.

Chrome DevTools: 10 Useful Tips & Tricks
Various tips and tricks to help you get the most out of Chrome DevTools
(from Web Design Weekly)

Learning

Awesome Cloud Native Trainings
"All the free trainings (with and without certificates) released from different companies supporting CNCF Projects and Kubernetes." (from CloudSecList)

The Docker, Kubernetes, Terraform, and AWS crash course series
"High quality learning material is hugely useful given the large number of technologies relevant to modern software development and operations. This set of crash course posts on Docker, Kubernetes, AWS and Terraform look super useful for anyone just getting started." (from DevOps Weekly)

Tools

Tauri
"An Electron alternative, written in Rust under MIT or MIT/Apache 2.0 license. The advantages of Electron combined with a fast, modern and secure base makes this a really cool project to consider for multi-platform apps. And the list of partners and sponsors makes me confident that it’ll stay at least for a while on the market." (from WDRL)

DevOps

Kubernetes 101
Kubernetes is one of the most exciting technologies in the world of DevOps. The article explains the concepts of it and some simple examples.

Minimal Container Images: Towards a More Secure Future
This post walks through the typical approaches in this space: minimal distributions, scratch and distroless. (from CloudSecList)

Design

Every programmer should care about UI design
"It’s way more common for people working on iOS/macOS projects to care about design than with some other platforms, but I still come across an occasional “I don’t need to care about it“. The points raised by this article are certainly worth reading if you’re in that camp!" (from iOS Dev Weekly)

UI Filler
Placeholders for your designs.
(from Web Design Weekly)

iOS

Awesome iOS widgets
A curated list of home screen widgets for apps on iOS 14!

Short notes on tech 25/2022

Tools

CyberChef
Simple, intuitive web app for analysing and decoding data without having to deal with complex tools or programming languages. CyberChef encourages both technical and non-technical people to explore data formats, encryption and compression.

Software development

The Art of Code Comments
Sarah Drasner talked at JSConf Hawaii 2020 about how commenting code is a more nuanced thing than we give it credit for. There is just not one right way or one reason to write a comment. The talk will dig into some of the many beneficial types of comments that might all serve a different purpose, followed by patterns we might want to avoid.

Does Laravel Scale?
"Jack Ellis elaborates on the question whether Laravel or PHP can scale." People usually tell how awful PHP is but what I've recently used it (newer versions) it was just like any other backend framework. And as Hannemann writes "It’s a very powerful, professional language with a huge ecosystem and it can be used to serve fast, efficient, reliable and readable codebases." (from WDRL)

Atkinson Hyperlegible font
"Atkinson Hyperlegible is a typeface created in partnership with Braille Institute. It has been developed specifically to increase legibility for readers with low vision, and to improve comprehension." (from WDW)

Security

Awesome Azure Penetration Testing
A collection of resources, tools and more for penetration testing and securing Microsoft's cloud platform. (from Cloud Security Reading List)

Miscellanous

Important PostgreSQL 14 update to avoid silent corruption of indexes
"PostgreSQL 14.4 release fixes an issue with all versions of PostgreSQL 14 that can lead to silent corruption of indexes."

Learn to write secure code with DevSecLab

There are lots of pitfalls in software development and creating a secure Web application needs some thought and keeping especially the OWASP Top-10 in mind. One effective way to learn secure software development is to learn by doing and that's what DevSecLab by Fraktal provides: teach developers to write secure code with hands-on exercises.

I got a chance to try the DevSecLab exercices with a free "trial" and here are my short notes about the content and thoughts about what I learned. Previously I've learned secure software development with Secure Code Warrior Secure Code Bootcamp, Kontra OWASP Top 10 for Web and more academic approach with Cyber Security Base MOOC so the topics and problems were familiar.

DevSecLab: Web Security Basics

The DevSecLab will teach you about:

  • The most common vulnerabilities in web applications,
  • How to spot vulnerabilities in code review
  • How to validate your findings with proof-of-concept exploits
  • Secure coding practices that keep your systems safe

The course is split into seven independent topics and you can work through them at your own pace in any order. The interactive challenges teach new tools and give new perspectives on daily work and each topic takes about 15–30-minutes.

  • Cross-Site Scripting (XSS): Hijacking a victim's browser by embedding JavaScript fragments in an application's inputs
  • SQL Injection: Accessing an application's database by embedding SQL fragments in its input
  • Broken Authentication: Weak or missing user identity checks on sensitive data or functionality
  • Broken Authorization: Weak or missing permission checks on sensitive data or functionality
  • Sensitive Data Exposure: Accidentally leaving secrets or confidential information publicly accessible
  • Cross-Site Request Forgery (CSRF): Tricking a victim's browser into performing actions on another website
  • Server-Side Request Forgery (SSRF): Tricking a backend server into performing HTTP requests on the attacker's behalf

The content of the course is well thought and covers the main issues in software development. Each topic is described in details by going from introduction to more detailed parts with appropriate exercises on the way.

DevSecLab: Introduction to CSRF

In each topic you get lessons ticked and unlocked by reading about the vulnerability and / or solving the exercises. The exercises can be all done with a web browser as shown below. Usually in the exercises you either need to write small about of code or use some other tools found in the web or in the course environment like gitleaks or fuff.

DevSecLab: exercise can be done with the browser

Some of the exercises require more thought what you should do the exploit the given application but fortunately there are hints to help you. At the end of the each topic there's "Dos & Don'ts" part which provides key points summarized for easy reference during daily work.

DevSecLab: Sensitive Data Exposure Dos and Don'ts

What I thought about it?

After the course you should have knowledge to identify, fix and prevent vulnerabilities in your web application code. And with hands-on approach with Dos and Don'ts at the end of each topic that goal is achieved.

What I liked about the course:

  • Shows what is wrong, how vulnerabilities can be exploited.
  • Hands down approach with embedded "browser" window of the application.
  • Suggestions of tools to use for testing (exploiting) like fuzzing.
  • Suggestions what you should do.
  • Dos and Don'ts

The overall difficulty was quite good regarding the hints you are given on the way and descriptions of the vulnerabilities. I didn't really count how many hours I spent doing the course. Although all of the topics were familiar more or less in practice I also learned some new things and what is also important, rehearsing the issues with new point of view.

DevSecLab has a free trial which you can check before buying the course. I found it useful and if you need it for compliance it really is "effortless" way to fulfill competence requirements.

Short notes on tech 22/2022

Worklife

GitLab's Guide to All-Remote
Good writeup of remote work in GitLab, i.a. it's benefits and drawbacks and tips to better remote.

DevOps

Honeycomb’s O’Reilly Book Observability Engineering
"Achieving Production Excellence by Charity Majors, Liz Fong-Jones, and George Miranda"

Set up a Terraform Pipeline with GitHub Actions and GitHub OIDC for AWS
A walkthrough of a Terraform pipeline setup. Most interesting for the use of OpenID Connect to remove the need for persistent credentials for AWS. (from Devops Weekly #590)

Terraform Best Practices for Better Infrastructure Management
Post which explores different best practices for Terraform and Infrastructure as Code, analyzes various options for handling and structuring Terraform projects, and shows how adopting helper tools could make our life easier. (from Cloud Security Reading List)

Observability 4 JVM Frameworks with Grafana in Java and Kotlin
(from Devops Weekly #591)

Security

A Review of the AWS Security Model
AWS have released their own security maturity model, but does it stack up against what we're seeing in real-world attacks and in the approaches being suggested by the rest of the AWS security community? (from Cloud Security Reading List)

Security Overview of AWS Fargate
Amazon's own security overview of Fargate, which is helpful for new adopters and deepens understanding of Fargate for current users. (from Cloud Security Reading List)

Override nested NPM dependency versions

Sometimes your JavaScript project's dependency contains a library which has a vulnerability and you're left with a question how to solve the issue. If the nested dependency (with vulnerability) is already fixed but the main dependency isn't, you can use overrides field of package.json as explained in StackOverflow answer.

You'll need a recently new version of npm cli v8.3.0 (2021-12-09) which comes with Node.js v16.14.0. Corresponding node.js and npm versions can be seen in the releases table.

In my case the problem was that express-openapi-validator contained a version of multer which used dicer with vulnerable version of busboy. The vulnerability was fixed in multer 1.4.4-lts.1 and now the task was to override the nested dependency.

The overrides section in package.json file provides a way to replace a package in your dependency tree with another version, or another package entirely. These changes can be scoped as specific or as vague as desired.

For example in my case I used:

{
  "overrides": {
    "express-openapi-validator": {
      "multer": "1.4.4-lts.1"
    }
  }
}

The overrides section is useful if you need to make specific changes to dependencies of your dependencies, for example replacing the version of a dependency with a known security issue, replacing an existing dependency with a fork or only override a package when it's a dependency of a particular package hierarchy.

And to ensure that you've correct Node.js and npm versions in use, add the following to the package.json.

"engines": {
    "node": ">=16.14",
    "npm": ">=8.3.0"
},

What did we learn here? About how to "patch" dependencies and how beneficial it is to read what new features comes with your tools. But in the end this all was more or less just a drill as the nested dependency of multer in express-openapi-validator was updated to the fixed version in the same day that it was released (it took around 10 days to multer have a fix).