Matthew Lindfield Seager

Scary iOS Exploit

Project Zero released details of a sustained (multi-year) and regularly updated iOS exploit suite.

I could barely follow a sentence of the iOS exploit chain articles but the last post demonstrating the capability of the implant is terrifying.

Even though the implant wouldn’t survive a reboot, by then the attacker (and anyone who happened to be listening to the unencrypted network traffic the malware sent back) already has your entire keychain.

As the author points out, this is a failed (detected/patched) exploit… it’s possible there are others still out there.

Calculating taxable portions

Xero doesn’t support line items that have a mix of GST and non-GST items. To add a mixed invoice you have to add the taxable amount on one line and the non-taxable amount on another. Unfortunately many invoices simply provide the total amount paid and the GST included, which means doing the calculations (estimations) yourself.

Most of the time you can just multiply the GST paid by 10 to find out the taxable portion and use that to derive the exempt portion:

# converted to cents for simplicity
total = 9794
gst = 566
taxable = gst * 10 # => 5660
exempt = total - gst - taxable # => 3568

In this case I happen to know the “correct” amounts were actually $56.65 taxable and $35.63 exempt but we can’t know that for sure based on the inputs we were provided. Our calculated answers are within the range of valid solutions and everything adds up correctly.

However, this formula doesn’t handle some (legal) edge cases. On a $9 invoice with $0.82 GST we end up with a taxable portion of $8.20 and an exempt portion of -$0.02. It’s an easy mistake to make.

To correctly derive valid values for the taxable and exempt portions in this case we need to add a conditional:

total = 900
gst = 82
taxable = gst * 10 # 820
if taxable + gst > total
  taxable = total - gst # 818
exempt = total - gst - taxable

Fantastic interview with Sandi Metz. There were two things she said that I wanted to write down but I was driving. No matter, I will happily listen to it again! (Overcast link)

This hardening guide for Rails apps is big but clearly written and has lots of links if you need more information about any steps. Bookmarking for future reference!……

Swedish school district in privacy hot water after tracking student attendance using facial recognition.

It’s getting easier and easier to do!

β€œThere is no quick fix, but there is a fix”

Something to remember with relationships, work and learning new skills… tricky lesson to learn though!

So apparently Stripe has 45 developers…

…whose entire job is inwards focused, trying to make the developer experience better for the rest of the development team! 🀯

How not to write error messages:

>[Error] Script lines: 1-9 --------------------------
 An unexpected token "" was found following "".  Expected tokens may include:  "
         table_name".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.22.29 

Today I learned that bundle open is a way to easily look inside Ruby gems!…

Enjoying the winter sunshine at the park

Today I learned a bit about β€œMutant Testing”… slight variations (mutations) in tests or test inputs. If a test still passes (a mutant survives) you have a potential gap/flaw in your code or tests… (Overcast link)

Signal is an excellent cross platform messaging app, a great alternative to WhatsApp for those wanting less Facebook in their lives.

I often keep browser tabs open on my phone with the vague thought that I’ll read/watch/share that later… and then never do anything with them.

Today I learned you can bulk close tabs by tapping and holding on the tab button (overlapping squares) in Mobile Safari

A mess is not a technical debt. A mess is just a mess. Technical debt decisions are made based on real project constraints. They are risky, but they can be beneficial. β€”Uncle Bob

Notes to future self:

  1. Watch out for integer division!
    9 / 10 # => 0 πŸ€”

  2. Order of operations matters!
    Float(9/10) # => 0.0 πŸ€”πŸ€”

  3. Ruby has you covered!
    Float(9)/10 # => 0.9 πŸ˜€
    9.to_f/10 # => 0.9 πŸ˜€
    9.fdiv(10) # => 0.9 πŸ˜€

VPN advice for schools (& probably most other businesses): when getting your firewall configured, make sure they set it up so it works with native VPN clients.

People shouldn’t need to install third party software (& kernel extensions!!!) just to connect to your network.

Raspberry Pi 4 is an impressive bit of kit! Quad core CPU, Gigabit ethernet, dual 4k displays & 4 USB-A ports (2 USB3).

Biggest disappointment is the β€œUSB-C” power port. I thought our Pi was DOA but it turns out it just needed a lower quality cable due to a design flaw πŸ€¦β€β™‚οΈ

Scammed πŸ˜”

I think I’m pretty savvy when it comes to online scams and phishing but it turns out I’m not so savvy in the real world πŸ˜”

A “fencing contractor” came to our door and said he’d been hired by our back neighbour to replace the (very dilapidated) wooden fence. He spent a while talking about site access and where to put the skip bin and whether it was okay to cut back one of our trees on the fenceline to make sure it didn’t impinge on the new fence.

Eventually I brought up the topic of payment and after “consulting with our neighbour” he came back and told me she’d agreed to pay the bulk of it as she was getting her (much longer) side fence done at the same time. Our half of the shared portion was only $500. That seemed like a bargain to me (I’m capable of physical labour but I really don’t enjoy it) so I readily agreed!

He “started working” (pulling some palings off the fence by hand) but said he couldn’t stay long as he had to provide a quote in another suburb. He told me that his colleagues would be back that arvo to complete the demolition. At this point he finally asked for a 50% deposit and I agreed.

I should have been more suspicious when he asked for cash instead of a bank transfer but I just assumed he was a dodgy contractor trying to stay below the tax man’s radar. I almost never pay cash for anything these days so I explained I’d have to go out and withdraw some.

I was actually in the middle of filling in a doorway in our house (again, I’m capable of physical labour, I just don’t enjoy it) so I went back to work and completely forgot about him or the cash. When he came to the door a little later I felt guilty for forgetting him. “Thankfully” I remembered I had some birthay cash stashed away so I fished it out and forked over $200.

That was the last I saw of “Eddy” or my $200. I later found out he scammed a lot more money out of our back neighbour.

With the benefit of hindsight there were lots of things I should have picked up on but he was very brazen, he added some convincing little details to his stories and he was very patient. It didn’t even occur to me at the time that he was anything other than a local lad trying to earn a (mostly) honest buck while also doing a solid for our elderly neighbour.

Despite the loss (and the embarassment!) there’s lots to be grateful for:

  • I didn’t give him as much as he asked for (that felt like a little victory in the moment… “I’ll teach him to ask for cash” πŸ™ƒ)
  • We don’t live paycheck to paycheck so we can “afford” this small loss (as opposed to our neighbour who is a pensioner and lost much more)
  • He didn’t come back that night and break into our house to steal the rest of our cash (our neighbour had a break in that same night and the last of her money was taken… she suspects it was the same person)
  • It spurred me into action about the fence… I might even have a crack at replacing it myself
  • The kids asked lots of questions and it gave us a chance to discuss what I did right and wrong and some possible life lessons
  • Best of all, it made me have my first proper conversation with our back neighbour which helped grow our relationship

And that’s not even mentioning the fact that, despite living in a “poor area” of Sydney, we are safe, comfortable and own our own home (some of it anyway… we still owe the bank a good chunk πŸ˜†). That probably puts us in the top 5 or 10% of the world’s wealthiest people!

My laptop fan started screaming… checked Activity Monitor and Safari CPU usage was at 122%

I closed the Twitter tab and within a few seconds the fans started to ease off.

First time I’ve logged in to Twitter for a while (wanted to ping someone), doesn’t make me miss it!

Pragma Precedence Preoccupation

The latest Ruby Weekly newsletter linked to a helpful blog post about magic comments (or pragmas) in Ruby by Mehdi Farsi. It’s a short read and I appreciated getting some more info on a topic I’ve never thought too much about. A couple of his examples made me a little suspicious though, so I did some more digging.

When specifying encoding, he demonstrates that the first magic comment is applied and any other encoding comments are ignored. That makes intuitive sense to me: you can’t change encoding part way through a file (at least I really hope you can’t, encodings cause enough confusion as it is!!!).

For his next two tests, Mehdi simply gave the magic comment two different settings at the top of the file and observed that the setting in the second one takes effect. He then concluded that only the last one is processed while the others are skipped.

Another possible conclusion is that both were processed and the different settings were in effect for different parts of the file. The way to test that would be to use a bigger example and turn the settings on and off multiple times:

# indentation-precedence-test.rb
# warn_indent: true
puts "\n*** Indentation Warnings: true ***"
def bad_indentation_1
"#{__method__} (line #{__LINE__})"
p bad_indentation_1

# warn_indent: false
puts "\n*** Indentation Warnings: false ***"

def bad_indentation_2
"#{__method__} (line #{__LINE__})"

p bad_indentation_2

# warn_indent: true
puts "\n*** Indentation Warnings: true ***"

def bad_indentation_3
"#{__method__} (line #{__LINE__})"

p bad_indentation_3

# warn_indent: false
puts "\n*** Indentation Warnings: false ***"

def bad_indentation_4
"#{__method__} (line #{__LINE__})"

p bad_indentation_4

In this test we try to turn the indentation warnings on and off (and on and off again). When I run it with ruby indentation-precedence-test.rb I get the following output:

indentation-precedece-test.rb:6: warning: mismatched indentations at 'end' with 'def' at 4
indentation-precedece-test.rb:24: warning: mismatched indentations at 'end' with 'def' at 22

*** Indentation Warnings: true ***
"bad_indentation_1 (line 5)"

*** Indentation Warnings: false ***
"bad_indentation_2 (line 14)"

*** Indentation Warnings: true ***
"bad_indentation_3 (line 23)"

*** Indentation Warnings: false ***
"bad_indentation_4 (line 32)"

Despite having four badly indented methods we only received two warnings; one for the first method (lines 4-6) and one for the third method (lines 22-24). These two methods were (badly) defined after turning warnings on. Conversely, the other two methods don’t cause warnings. They were (badly) defined after turning warnings off. This confirms that all of the warn_indent settings in the magic comments are applied, simply changing the state from that point in the file onwards.

But what about in other files when you require them? Does the setting carry over?

# indentation-test-requiring.rb
puts "\n*** Main file, Indentation Warnings: default ***"

def bad_indentation_1
"#{__method__} (line #{__LINE__})"

p bad_indentation_1

# warn_indent: true
puts "\n*** Main file, Indentation Warnings: true ***"

def bad_indentation_2
"#{__method__} (line #{__LINE__})"

p bad_indentation_2

require_relative 'indentation-test-inherit.rb'

# warn_indent: false
puts "\n*** Indentation Warnings: false ***"

def bad_indentation_4
"#{__method__} (line #{__LINE__})"

p bad_indentation_4

require_relative 'indentation-test-override.rb'

puts "\n*** Main file, Indentation Warnings: did they change??? ***"

def bad_indentation_6
"#{__method__} (line #{__LINE__})"

p bad_indentation_6
# indentation-test-inherit.rb
puts "\n*** New file, Indentation Warnings: Do they inherit??? ***"

def bad_indentation_3
"#{__method__} (line #{__LINE__})"

p bad_indentation_3
# indentation-test-override.rb
# warn_indent: true
puts "\n*** Another new file, Indentation Warnings: true ***"

def bad_indentation_5
"#{__method__} (line #{__LINE__})"

p bad_indentation_5

In this example we only get two warnings, one for method 2 in the main file and one for method 5 in the “override” file (that we explicitly turned them back on for).

This shows us a few things:

  1. Those warnings are off in a file by default (method 1 and method 3)
  2. Turning it on for one file doesn’t turn it on for files that are later required (on for method 2, off for method 3 in a new file)
  3. Turning it on in a required file doesn’t effect methods defined after that point in the requiring file (on for method 5 in a second new file, still off for method 6 in the original file)
  4. The warnings are output when the file is first parsed (which further explains point 3 above)

But do the same rules hold for frozen string literals?

Let’s start by confirming the default state for frozen string literals is off:

# frozens-test.rb
string_1 = 'frozen? 1'
p "string_1.frozen?: #{string_1.frozen?}" # => "string_1.frozen?: false"

Now let’s turn it on for the next one:

# frozens-test.rb
string_1 = 'frozen? 1'
p "string_1.frozen?: #{string_1.frozen?}" # => "string_1.frozen?: false"

# frozen_string_literal: true
string_2 = 'frozen? 2'
p "string_2.frozen?: #{string_2.frozen?}" # => "string_2.frozen?: false"

Wait, what!? It’s not frozen! Unlike the indentations warning, it seems this particular magic comment has to come at the top of the file. But in Mehdi’s test he had another comment before it. Let’s test if all comments and whitespace are okay:

# frozens-test-2.rb

# frozen_string_literal: true
# Random comment after turning string literals on...

#... and lots of white space before we turn them back off
# frozen_string_literal: false

# Different comment types are fine...

  If you want to read
  a block-commented Haiku
  this will have to do


# Other pragmas (magic comments) are fine too
# # warn_indent: true

# We can still turn them on...
# frozen_string_literal: true
string_3 = 'frozen? 3'
p "string_3.frozen?: #{string_3.frozen?}" # => "string_3.frozen?: true"

It turns out comments are fine, white space is fine, and other pragmas (magic comments) are fine.

So maybe it just needs to be before any strings?

# frozens-test-3.rb

2 + 2

# frozen_string_literal: true
string_4 = 'frozen? 4'
p "string_4.frozen?: #{string_4.frozen?}" # => "string_4.frozen?: false"

Nope! Adding 2 numbers together (or even defining an empty method), prevents it from being used. In my testing, the only vaguely code-like things that seem to be allowed before this magic comment are pointless references to existing objects:

# frozens-test-4.rb

# nil is okay:

# Mentioning special variables (like the last exception) seems to be okay

# Referencing the args array is okay too, even if it's not empty

# Referencing the file path is also fine

# frozen_string_literal: true
string_5 = 'frozen? 5'
p "string_5.frozen?: #{string_5.frozen?}" # => "string_5.frozen?: true"

And just when you thought I’d plumbed the boring depths of this, I found one last exception to the rule:

# frozens-test-5.rb

# It doesn't like special variables on consecutive lines!!!

# frozen_string_literal: true
string_6 = 'frozen? 6'
p "string_6.frozen?: #{string_6.frozen?}" # => "string_6.frozen?: false"

So in conclusion:

  1. The # frozen_string_literal has to come before any (useful) code
  2. If you set it multiple times, the final setting (before any useful code) wins

Kiba is really nice for doing ETL work in Ruby! It strikes a great balance between providing all the tools you need to be productive without forcing you down any particular path or to learn huge amounts of syntax! Very flexible and powerful!

Netflix in the Classroom... kind of

Netflix in the Classroom… kind of

According to its terms of use, Netflix can’t be used in a classroom, it’s only for personal use. However, I recently learned there are certain Netflix documentaries that Netflix grants special permissions to allow educational streamings (e.g. Take Your Pills).

That sounds fantastic but it doesn’t seem like Netflix have actually thought about the intended audience for this as the user experience to identify these documentaries is awful.

If you’re a teacher, here are the steps to find out which documentaries are available:

  1. Navigate to a section of the PR site to see Netflix originals (as far as I know, only originals are eligible for these special permissions)
  2. Click on ‘All Alphabetical’ to get the full list
  3. We only want documentaries so click on the ‘Category’ heading to group the titles by category
  4. It defaults to sorting the categories reverse alphabetically so click on the ‘Category’ heading again to sort alphabetically (this moves the documentaries closer to the top and means we don’t have to click through 45 pages of films, series & stand-up comedy, just one or two pages of Anime)
  5. Scroll to the bottom, looking for documentaries. If there are none click ‘Next’
  6. Repeat step 5 until you’re past the ‘Anime Series’ category. Click/tap on the first documentary to open it up (note that the site seems to be using some sort of custom Javascript click detection so you can’t do normal web browser behaviour, like open the link in a new window. This will become a problem later)
  7. Check if the documentaty permits education screenings. If so, copy the URL (e.g. somewhere for posterity… you’ll need it later to prove you’re allowed to screen the title
  8. Click/tap back in your browser to go to the listing page. Notice that when you go back the page number stays the same but the page reloads, losing your scroll position and sorting preferences
  9. Click the ‘Category’ heading to group by category, reverse-alphabetically (see also point 3 above)
  10. Click the ‘Category’ heading again to group by category, alphabetically (see also point 4 above)
  11. Find the next documentary (you’ll have to manually remember what you’re up to… they’re non-standard links so, unlike a standard web page, you don’t get any indication which links you’ve already clicked on) and click/tap on it to open it up
  12. Repeat steps 7-11 for the other 132 titles (and growing).

On a brand new laptop with no distractions and an uncontested 100Mbps Internet connection (three things I wouldn’t count on teachers in most schools having) I was able to check three documentaries in just under a minute, not including the time to save the URL if it was one of the small percentage that are permitted for educational use (nor the time to navigate to the next page when you finish one).

All up that’s going to be 40+ painful minutes of clicking and navigating for a list of about 25 education permitted documentaries (extrapolating from a fairly small sample).

A far better experience would be if the list view contained a little icon of some sort (a mortaboard hat icon perhaps) indicating which documentaries permit education screenings.

Standard HTML links (that allow opening links in a new tab and seeing which links have already been visited) would also be a huge improvement.

I contacted Netflix PR (the part of the organisation that hosts the “Only on Netflix” portion of the site) over a week ago and asked them for more information about the titles available under this service and whether they were aware of the usability and accessibility issues but I didn’t receive even an automated reply. I will update this post if they get back to me.

I used the kiba gem for an ETL process today. My initial impressions are very positive! It lets you take a data source and build a “pipeline” to process the data using a declarative syntax. I think I’ll be using it a fair bit more!…

An anesthesiologist gives a great little (< 20 min) talk on how failure research applies to web apps.…

All about resilience in systems and the inevitable pressures that are constantly pushing the operating point closer to the failure boundary.

In my recent security travels, I found an article by the author of bcrypt-ruby on How To Safely Store A Password.…

It was last updated in 2011 but I think it holds up well.