My Rabbit R1 just arrived. I haven’t played with it enough yet to have an opinion on the software’s usability. The hardware itself is nice, though. Photos can’t accurately convey how very orange! the thing is. It just about glows in the dark.

A cardboard box with diamonds on the top and º + º on the front so that it looks kind of like a bunny from the right angle.An open box with plain grey foam.The R1 in its clear plastic case that also doubles as a stand.A Rabbit R1 laying on its foam packing. It's reflecting light so brightly that it almost looks like the camera's broken, but no, it really is that colorful.

I wish OmniFocus used perspectives in Forecast

I wish OmniFocus would replace the way its Forecast view selects items to display with a user-selectable perspective. Then I could make my own choices about what to include, and OmniFocus would display those items in its handy integrated view alongside calendar events.

I can’t make those choices today. For example, the Forecast view doesn’t allow me to include actions that have a defer date in the past. That is, once an action is past its “start date” and available to be worked on, it no longer shows up on Forecast’s Today tab, or even in the Past tab. This is all the configuration available to decide what the Forecast view should show:

Forecast configuration tab

That’s one place I think Things is better than OmniFocus: If I have an action like “pay the rent (after the 20th of the month)”, the Things Today view will still show that action as something I could and should be doing on the 22nd of the month.

Purists might argue that I’m using OmniFocus wrong. I shouldn’t be leaning on the Forecast view at all, but should be regularly checking my tags and projects to see what I should be doing. That workflow isn’t the right fit for me. I know. I’ve tried it many times. What does work is a nice Today view that shows all my available scheduled actions in one place, along with actions I’ve tagged with “Today” during a review. I have a personal items perspective like that which ends up looking much like Things if I squint at it the right way:

Perspective configuration tab

Notice that the Forecast configuration looks an awful lot like a pared-down version of a regular perspective. If I had a magic wand to wave, I’d remove the “Items” checkboxes from the “In Forecast, include” and “Today includes” sections and replace them with the name of the perspective that would select all the items I wanted to show on the Forecast. Ta-da, done. Then I could customize the Forecast to make it perfect for my own needs. Others could make their own perspective, or use a default that OmniGroup could include to emulate the current behavior. Alternatively, a perspective could gain a “Display as Forecast” checkbox where I could have multiple Forecasts, each with its own filtered view of items. Tell me a separate “Personal Forecast” and “Work Forecast” view doesn’t sound nice. Imagine that you could associate each one with the appropriate focus filter so that they show up automatically when you’re doing personal or work things on your computer. The heart flutters!

Please consider this, Omni Group. OmniFocus is powerfully customizable in so many ways! I’d be delighted if this one last set-in-stone limitation were removed.

Palo Alto's exploited Python code

watchTowr Labs has a nice blog post dissecting CVE-2024-3400. It’s very readable. Go check it out.

The awfulness of Palo Alto’s Python code in this snippet stood out to me:

def some_function():
    ...
    if source_ip_str is not None and source_ip_str != "": 
        curl_cmd = "/usr/bin/curl -v -H \"Content-Type: application/octet-stream\" -X PUT \"%s\" --data-binary @%s --capath %s --interface %s" \
                     %(signedUrl, fname, capath, source_ip_str)
    else:
        curl_cmd = "/usr/bin/curl -v -H \"Content-Type: application/octet-stream\" -X PUT \"%s\" --data-binary @%s --capath %s" \
                     %(signedUrl, fname, capath)
    if dbg:
        logger.info("S2: XFILE: send_file: curl cmd: '%s'" %curl_cmd)
    stat, rsp, err, pid = pansys(curl_cmd, shell=True, timeout=250)
    ...

def dosys(self, command, close_fds=True, shell=False, timeout=30, first_wait=None):
    """call shell-command and either return its output or kill it
       if it doesn't normally exit within timeout seconds"""

    # Define dosys specific constants here
    PANSYS_POST_SIGKILL_RETRY_COUNT = 5

    # how long to pause between poll-readline-readline cycles
    PANSYS_DOSYS_PAUSE = 0.1

    # Use first_wait if time to complete is lengthy and can be estimated 
    if first_wait == None:
        first_wait = PANSYS_DOSYS_PAUSE

    # restrict the maximum possible dosys timeout
    PANSYS_DOSYS_MAX_TIMEOUT = 23 * 60 * 60
    # Can support upto 2GB per stream
    out = StringIO()
    err = StringIO()

    try:
        if shell:
            cmd = command
        else:
            cmd = command.split()
    except AttributeError: cmd = command

    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, bufsize=1, shell=shell,
             stderr=subprocess.PIPE, close_fds=close_fds, universal_newlines=True)
    timer = pansys_timer(timeout, PANSYS_DOSYS_MAX_TIMEOUT)

It uses string building to create a curl command line. Then it passes that command line down into a function that calls subprocess.Popen(cmd_line, shell=True). What? No! Don’t ever do that!

I fed that code into the open source bandit static analyzer. It flagged this code with a high severity, high confidence finding:

ᐅ bandit pan.py
[main]  INFO    profile include tests: None
[main]  INFO    profile exclude tests: None
[main]  INFO    cli include tests: None
[main]  INFO    cli exclude tests: None
[main]  INFO    running on Python 3.12.1
Run started:2024-04-16 17:14:52.240258

Test results:
>> Issue: [B604:any_other_function_with_shell_equals_true] Function call with shell=True parameter identified, possible security issue.
   Severity: Medium   Confidence: Low
   CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
   More Info: https://bandit.readthedocs.io/en/1.7.8/plugins/b604_any_other_function_with_shell_equals_true.html
   Location: ./pan.py:14:26
13              logger.info("S2: XFILE: send_file: curl cmd: '%s'" % curl_cmd)
14          stat, rsp, err, pid = pansys(curl_cmd, shell=True, timeout=250)
15

--------------------------------------------------
>> Issue: [B602:subprocess_popen_with_shell_equals_true] subprocess call with shell=True identified, security issue.
   Severity: High   Confidence: High
   CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
   More Info: https://bandit.readthedocs.io/en/1.7.8/plugins/b602_subprocess_popen_with_shell_equals_true.html
   Location: ./pan.py:49:8
48              bufsize=1,
49              shell=shell,
50              stderr=subprocess.PIPE,
51              close_fds=close_fds,
52              universal_newlines=True,
53          )
54          timer = pansys_timer(timeout, PANSYS_DOSYS_MAX_TIMEOUT)

--------------------------------------------------

Code scanned:
        Total lines of code: 41
        Total lines skipped (#nosec): 0

Run metrics:
        Total issues (by severity):
                Undefined: 0
                Low: 0
                Medium: 1
                High: 1
        Total issues (by confidence):
                Undefined: 0
                Low: 1
                Medium: 0
                High: 1
Files skipped (0):

From that we can infer that Palo Alto does not use effective static analysis on their Python code. If they did, this code would not have made it to production.

I fought State Farm (and won)

State Farm claimed we owed them money. I said we didn’t. They pursued it. I countered. They ended up owing us money instead.

My wife’s small business purchased our unemployment insurance through State Farm until we sold the company a couple years ago. Unemployment insurance premiums are proportional to your payroll: you pay the insurer a certain percentage of each dollar you pay your employees. When you cancel a policy, you reconcile your payroll numbers with them to settle up one last time.

State Farm said they estimated we’d been paying our employees $100,000 a year1. Therefore, by their reckoning, we owed them another $1,000 in additional premiums as if we’d paid out $100,000 in payroll that final year, even though we sold the business in May. They sent me an audit form to complete if we wanted to use our true numbers instead of their estimate. I submitted their form and promptly forgot all about it.

6 months later I got an email from our insurance agent saying that we still owed State Farm $1,000. I replied that we did not and that they needed to recompute our supposed debt using the real numbers that I’d submitted to the audit.

We had the same interaction about 6 months later, then again another 6 months after that. State Farm claimed they’d sent us all the information in writing. We found that they’d been sending letters to the old office that we’d lost access to on the day we sold the business, and the new owner never bothered forwarding them to us. Regardless, I wasn’t about to pay them the $1,000.

I got a more urgent email from our agent toward the end of last year. State Farm wanted their money and were turning our account over to a bill collector if we didn’t pay it. I replied and made our position clear: if State Farm would put it in writing that they had computed our amount due based on our real payroll numbers, and if they mailed that to us at our current home address and not the old business address we weren’t at anymore, only then would I pay them.

Again, silence.

A couple months ago I got a call from a bill collector. He was OK to talk to. I told him his customer was smoking crack and he laughed. Then I repeated our demands: I wanted State Farm to give us an itemized invoice showing their accurate calculations, and I wanted it sent to our house. I promised him that if both happened, I’d cheerfully make arrangements to pay the invoice in full immediately. He said that was reasonable. We parted ways.

However, I’d run out of patience. I filed a formal complaint with California’s Department of Insurance explaining our side of the conversation, asking them to rule on our behalf, and loading them with evidence proving our argument.

2 weeks later, the Department of Insurance replied saying that we needed to appeal the dispute through State Farm’s internal process before involving the state. Their letter contained details about the precise person we needed to contact and the legal jargon to use.

I did that. I got a response from that person yesterday. Their letter contained the itemized calculations I’d asked for all along, a final ruling that State Farm owes us $200, and a promise to mail a refund check to our correct address by the end of the week.

It took 2 years for State Farm to straighten out their math. They could have offered to write off our “debt” a year ago and stop pestering us. I would have accepted that. Instead, they kept it up and lost.

Yay me!

If that check isn’t here in the next few days, I have the number of a bill collector I might hire.


  1. All numbers are fictional for storytelling purposes. ↩︎

Tennessee bans kids playing in sprinklers

Tennessee’s new “chemtrail bill” is inherently ludicrous. It’s also as poorly written as cold be expected. From the bill itself:

The intentional injection, release, or dispersion, by any means, of chemicals, chemical compounds, substances, or apparatus within the borders of this state into the atmosphere with the express purpose of affecting temperature, weather, or the intensity of the sunlight is prohibited.

Strictly speaking, the big government types in Tennessee are banning residents from setting up lawn sprinklers for their kids to play in on a hot day.

On the plus side, it will be explicitly illegal to “roll coal” with the intent of covering another person in a cloud of smoke.

Fixing Things with Keyboard Maestro

I can’t help playing with Things sometimes. Even though there are plenty of reasons not to use Things, it’s pretty. It’s my attractive nuisance. However, I can’t stand its inability to complete repeating items before they’re scheduled, so I fixed it.

You know I like Keyboard Maestro and Shortcuts. I combined them to work around Things’s glaring shortcoming. So can you!

First, install my Shortcut, Things: Get ID of current selection. Look inside it. It only copies the internal ID of the currently selected item to the clipboard.

Then, install my Things: Repeat action early Keyboard Maestro macro and set it to trigger with a hotkey you like. Since cmd-K is the using Things shortcut for completing an item, I set mine to trigger when I press shift-cmd-K. Then it takes these steps:

  1. Calls the Shortcut to get the ID of the current Things item.
  2. Goes to the latest completed copy of that item.
  3. Duplicates the completed copy and navigates to the new copy.
  4. Calls the Shortcut to get the ID of the new copy.
  5. Marks that copy as “open”, that is, not completed.
  6. That causes Things to move the copy from the “logged items” section back up to the list of open items, so the macro calls a Things URL to jump back to the re-opened, copied item via its ID that we saved a couple steps ago.
  7. Marks the new copy as deleted. That causes Things to update the repeating task so that its When and/or Deadline dates are relative to today.
  8. Calls the Things URL to jump all the way back to the repeating item, via its ID that we saved in the first step.

Whew. That’s a handful, huh? But it mostly works!

Caveats:

  1. There’s no error handling. Keyboard Maestro just blindly sends keyboard presses and menu selections to Things and assumes that everything’s going well.
  2. I’m not really sure what would happen if you run the shortcut with no items selected, or more than 1 item.
  3. If it’s been ages since the last time the item was completed and there’s no longer a “latest” item to go to, I don’t know what happens next.

In short, use this at your own risk. There are a dozen things it could be doing better or more safely and I haven’t (yet) done any of them. Still, it works! If I squint hard enough and get lucky, the new macro makes Things repeating actions work like every other to-do app in existence. I’m calling that a win.

Testing my fountain pen inks' water resistance

I wondered how water-resistant the inks from the various pens on my desk would be. For my unscientific test, I wrote a small sample of text with each of these inks on a sheet of plain white copier paper:

Don’t judge my penmanship. I know. I know.

Dry inks

I let them dry overnight. Then I used a wet toothpick to put one drop of water on each sample, being careful not to move the paper or water at all. The results were mixed:

Wetted inks
  • Jacques Herbin melted away.
  • LAMY was as ruined.
  • Herbin feathered badly but was readable.
  • Noodler didn’t notice.
  • Fisher blurred slightly.
  • Zebra: what water?
  • Pentel was also lost.

While I don’t make a habit of getting my notes wet, if were carrying a notebook out of the house, I’d pick one of the survivors. Baystate Blue and the Zebra F-701 weren’t affected. The space pen was fine, and Perle Noire was readable. I wouldn’t risk Émeraude de Chivor, LAMY, or EnerGel to rain, drops of water off an ice tea glass, or even damp hands.

My notebooks often spend their entire lives on my desk and I don’t exactly take them scuba diving. Yet, this is a good thing to know.

For my next experiment, I’m going to let the same inks dry for a week before testing.


Followup 2024-03-17: I tried again after letting the inks sit for 2 weeks. The results were similar to the original test:

Two weeks later

The extra time didn’t let them “cure” or “harden” or “set in” or such.

Reliable Shortcuts with Stream Deck and Keyboard Maestro

I talked myself into buying a Stream Deck to control my Mac. I didn’t want one for the media features. I wanted a cool, programmable external keyboard-like thing to trigger actions. For example, I have buttons to turn my office lights on and off, toggle between playing sounds through my external speakers and headphones, and open my notes app to the Today’s Journal page. I like it.

Most docs I found suggest using the Shortcuts plugin to execute Apple Shortcuts. I recommend that you use Keyboard Maestro instead. The “Shortcuts” plugin is neat in principle. It’s free. It looks like exactly the right tool for the job. For me, it’s not. Using the most current macOS (version 14.3.1), Stream Deck app (v6.5.0), and plugin (v1.0.7.1), keypresses work about half the time. After using the setup for a few days straight, it always hangs and stops responding altogether until I quit and restart the Stream Deck app. It’s frustrating to have this nice device to boost productivity, then have to pause for a beat every time I’ve used it to see if it worked.

The Keyboard Maestro setup’s experience has been the opposite. Once configured, if I press a button, that button does what it’s supposed to do 100% of the time. It has some drawbacks: it’s slightly more complex to configure, and you have to pay for Keyboard Maestro (which if you’re a Mac power user, you’ll want to do anyway). Still, the result has been worth it.

Here’s how I used it to build the toggle I mentioned that switches between speakers and headphones.

First, I created Shortcuts called “SoundSource: Output to Headphones” and “SoundSource: Output to Speakers”, with each Shortcut doing the expected thing. The names don’t matter: I could have called them “Spam” and “Eggs” for all my Mac would care. I just like being verbose so I can quickly find things again next time I want to tweak them.

The Shortcuts

Next, I made Keyboard Maestro macros that execute those Shortcuts:

"SoundSource: Output to Headphones" (without trigger) "SoundSource: Output to Speakers" (without trigger)

Then I opened the Stream Deck app to create the “Multi Action Switch” button. I put mine on row 1, column 3. That’ll be important in a moment.

Toggle 1 Toggle 2

When you create a Keyboard Maestro action inside a Multi Action Switch, the Stream Deck app doesn’t fill in the “Virtual Row” and “Virtual Column” values like it would if you put the Keyboard Maestro action directly into an empty key. That’s OK. We’re going to change the column value anyway! See how I used Virtual Columns “301” and “302”? That lets the Keyboard Maestro app treat these as separate buttons. The Stream Deck app will do the work of remembering which action we’re currently on.

With that done, I went back into the Keyboard Maestro editor and added “USB Device Key Triggers” to each macro. When it was waiting for me to press a button, I tapped the physical Stream Deck button I was setting up.

"SoundSource: Output to Headphones" (with trigger) "SoundSource: Output to Speakers" (with trigger)

That’s a little bit more complicated than the “Shortcuts plugin” setup, but only a little bit:

  • I’d have to create the Shortcuts either way.
  • I’d have to create the Multi Action Switch either way.
  • Instead of using the “Shortcuts” plugin to run Shortcuts directly, I send a trigger to Keyboard Maestro and have it run the Shortcuts.

In exchange for this smidgen of extra one-time work, now my Stream Deck buttons work perfectly and instantly every time I press them. I don’t hesitate to see if the effect I wanted to happen had indeed happened because I can trust that it did. That made an enormous difference in how productively I can use the little Stream Deck.

The Internet is a rough neighborhood

This week I stood up a new firewall in front of my home network. This one has much better logging than the old one, and I’ve been watching the block reports.

A screenshot of blocked inbound connection attempts, originating from all over the world.

Real talk, friends: DO. NOT. expose a machine to the open Internet unless you’re 100% confident it’s bulletproof.

“I run my service on a custom port!” Doesn’t matter.

“I use IPv6!” Doesn’t matter.

“I’m just a nobody!” Doesn’t matter.

Practice safer networking, every time, all the time.

Integrate Things with Focus

I use the Things task manager to keep track of what I need to do. I use the Focus pomodoro timer to help myself focus on a task that I’m actively working on.

Focus integrates well with another task manager, OmniFocus: you can drag an action from OmniFocus into Focus to create a task to work on, and that task will have a button that links back to the original OmniFocus action. Super convenient! It doesn’t play well with Things, though. If you try the same process, you’ll end up with multiple separate actions for each of the Things to-do’s various properties.

For example, this to-do has the title, note, checklist, tags, when, and deadline options filled in:

A Things to-do with lots of options set

Dragging it to Focus creates a whole mess of random tasks:

Focus with 8 unrelated tasks

That’s not helpful. We can do better.

First, I wrote a shortcut using Things’s shiny new Shortcuts actions. For each to-do currently selected in Things, it uses Focus’s URL scheme to create a Focus task with the item’s title, notes, and due date, and a link back to the item in Things.

Second, I made a Keyboard Maestro hot key macro, available only in Things, that executes my shortcut. When I select the to-do item above and press “option-F”, I get one single task with all the details set:

Focus with 1 well-configured task

If I click the link icon next to the task’s title, Things opens with that to-do selected.

Ta-da! The workflow is slightly different than with OmniFocus, but only a little bit, and the result is just as useful.

Surprise eero hardware end-of-life

Amazon is ending software support for 1st generation eero devices at the end of September 2022. That’s fine. You can’t support old hardware forever, and five years is a decent run.

But it’s not OK that I got less than a month’s notice that it was happening, and no email or app notifications. I happened to open the eero app for unrelated reasons and saw a banner telling me my hardware will be obsolete later this month. That’s unacceptably short notice that the hardware is all but dead. Sure, it may keep working for a while, but without security updates or routine bug fixes, it’s not anything I’d want to depend on. If I’d received any other notice whatsoever, I would have been investigating hardware upgrades, reading the various sale emails they’d sent me, and otherwise preparing for the day. Now I have to scramble to fix something that I didn’t know needed fixed, and I don’t appreciate it.

To the folks at eero: this is a managed system. You have my contact information and know what hardware I’m using. This would have been an excellent opportunity for you to let me know about this a few months ago. You could have suggested appropriate hardware upgrades and turned it into a sales opportunity. As your customer, I would have liked that.

eero death notice

Trying (and Failing) to hack the Wall of Sheep

The Wall of Sheep is a popular exhibit at DEF CON. Participants run packet sniffers on an insecure Wi-Fi network and try to catch people logging into unencrypted websites and other services. If they see that happening, they post the person’s username and password on a giant display. It looks something like:

Sample Wall of Sheep

That’s an excellent reminder to be careful when you’re connected to an unknown network, and not to send your login credentials out in the open.

From the first time I saw it, though, I had to wonder: is the wall itself hackable? Could I make it look like this instead?

Snoop onto them, as they snoop onto us.

The idea kept bouncing around the back of my mind until I added it to my to-do list so I could stop thinking about it. I had to at least try it.

To do: hack the wall!

Assumptions

I know nothing about the Wall of Sheep’s internal workings. That’s deliberate. I wanted to test this for the fun of it, and part of the challenge was to see how far I could get without any knowledge of it. I had to make a few assumptions:

  1. If you’re connected to the right Wi-Fi network and submit credentials in plaintext, they’ll be shown on the wall.
  2. The process of getting captured credentials on the wall is automated.
  3. The wall is rendered by a web browser.
  4. The wall’s software has been around for a while and wasn’t written to be particularly secure. After all, it’s on the attacking end, right?
  5. No one’s tried this before, so no one’s fixed it before.

Choosing the attack

If the above assumptions are true, the obvious attack vector is Cross Site Scripting (XSS). The method is to create a snippet of JavaScript and then trick the Wall of Sheep into displaying — and executing — it. This should work:

<script type="text/javascript">alert("I was here.");</script>

But how do I get that onto the board? The password field is usually censored, such as hunter2 being masked to hunt***. That would destroy the payload, so that wouldn’t work. Is there a way to make a DNS hostname that renders correctly? Eh, maybe, but crafting that sounds like work. (Note to self: but boy, wouldn’t that wreak havoc on the web? Huh. I’ve gotta look into that.)

However, look at that lovely login field. It’s just sitting out there in full, uncensored, plaintext glory. Jackpot! That’s where I’ll inject the JavaScript.

Setting up a webserver

This attack requires a webserver to send those faked credentials to. For ease of implementation, I configured HTTP Basic authentication with:

  • Username: Me<script ...
  • Password: lol
Remember how I've wanted to do this for years? Guess who suddenly remembered to do it on the last day of DEF CON. Everything after this was done on my iPhone with Vim in an SSH client. This was not an ideal way to do something technical. Learn from my mistakes: failing to plan is planning to fail.

Getting onto the DefCon-open Wi-Fi

You brought a burner device, right? I didn’t. What could possibly go wrong connecting an off-the-shelf device to an open network at DEF CON! YOLO.

Visiting the web page

I logged into the page on my webserver’s bare IP address, watched the board, and… nothing. I reloaded it; nothing. I looked around to see if any of the participants looked like they might’ve found something; still nothing. Rats.

Enlisting help

Jan and Pat1 were participants sitting near where I was setting this up. I needed their assistance but didn’t want to outright ask for it. I started posing innocent questions to Jan: “Hey, what are you working on? What’s Wireshark?” While they kindly explained in general terms, they were understandably more interested in their own project than tutoring a passerby. Pat was more willing to teach me and I pulled up a chair to sit with them. They patiently answered my questions and pointed to interesting things on their screen. They also noticed fairly quickly that I was regularly reloading a page on my phone as I watched them. “Hey, uh, are you trying to get caught?” “Maaaaybe…” “Why?” I gave them a quick explanation of my project and they instantly bought in:

Pat: Do you think this’ll work?
Me: Probably not, but it’s worth a shot.
Pat: Oh, wow. If it does, this will be legendary!

I had a helper. Soon after, Jan noticed we were up to something, leading to one of my favorite exchanges at DEF CON:

Jan: Are you two trying to get something up there on the board?
Me, grinning: Yeah. It’s a JavaScript injection.
Jan, wide-eyed: Who the hell are you?

Thank you, Jan. I felt like a bona fide Security Researcher after that.

Another random visitor saw us huddled and asked if we were trying to hack something. Jan looked at me, looked at the visitor, said “nope”, and looked back at me. I winked at Jan. Jan nodded back. The visitor squinted at us and walked off. Jan had my back.

Pat and Jan were awesome. When we couldn't capture my phone's request, Pat asked if I happened to be on a VPN. facepalm. Yes, I had iCloud Private Relay turned on globally.

Social engineering a Shepherd

After experimentation, we had usable Wireshark captures of me logging into my website. However, they weren’t being displayed on the Wall of Sheep. It turned out that my assumption was wrong: we had to demonstrate the capture to a “Shepherd” running the contest. Pat called one over. We showed them Pat’s capture, but they weren’t convinced at first. Most website logins are through a form POSTed to the server, not through HTTP Basic authentication. The Shepherd was also skeptical that the login was successful because the server was returning the default “welcome to Nginx!” page and not something personalized for the (obviously fake) username. I leaned very hard into the “innocent observer” role, asking questions like “but isn’t that what a successful capture looks like?” and “golly gee, it looks right to me. Don’t you think?” and “it looks suspicious to me, too, but couldn’t we try it and see what happens?” Our Shepherd seemed almost ready to go along with it — until they burned my plan to the ground.

Defeat

I asked the Shepherd how a login goes from being captured to being shown on the Wall of Sheep. Their reply doomed our fun: “I’d type it in.” Oh no. That’s not good. “Isn’t it automatic?”, I asked. The Shepherd paused to rub the bridge of their nose. “Well,” they sighed, “it was until people started sending a bunch of vile usernames and passwords and kind of ruined it2, so now we have to moderate the process.” I wasn’t giving up, though. “Could you type that username to see what happens?” “It’d just show up like that,” they replied. “Could we try it?”, I pleaded. “I mean, it’s just text. Um, that’s not a web page”, they countered.

What.

And then for the first time ever, I saw a flashing cursor down in the bottom corner of the Wall of Sheep. My heart sunk. “Is that Excel or something?” They grinned: “it’s just some old software we run.”

Disaster.

Regrouping

That’s when I formally gave up on this attempt. If it were ever possible to hack the Wall of Sheep, it wasn’t on that day. That doesn’t mean I’m abandoning this forever, though. Next year, I’m going to make a smarter effort, by:

  • Setting this up in advance. Again, Vim over SSH on a phone sucks. I’ll have the fake login working before I leave home.
  • Getting there earlier. If the Wall of Sheep is ever going to be automated and rendered in a browser, it’ll be at the opening of DEF CON before anyone’s polluted the waters.
  • Using a more common authentication method than HTTP Basic auth, like a typical login form.
  • Making the resulting page look like I’d really logged into a legitimate service.
  • Bringing a burner device, because putting my own personal device on that specific Wi-Fi network was not the best idea I’ve ever had.

And if Jan and Pat are around, I’m recruiting their help again.

To do: hack the wall harder!

  1. I didn’t get anyone’s names, or their permission to describe them. Fake names are all you get. ↩︎

  2. I appreciate the irony that I’m complaining about hackers getting stuff to show up on the Wall of Sheep in a post where I’m talking about getting stuff to show up on the Wall of Sheep. The first rule of a good prank, though, is “don’t be a jackass and ruin it for everyone else”. I was going for something that I hoped the Shepherds would find amusing and wasn’t trying to get racial slurs and other vile junk to show up on a big screen. Don’t be that person. ↩︎

...And Back to OmniFocus

I recently wrote about switching from OmniFocus to Reminders and gave a lot of reasons why I thought that was a good plan. I was wrong and I’ve since moved back.

Apple has made Reminders into a solid app with a lot of nice features, but I realized I’ve been taking OmniFocus for granted. First, I sorely missed its “defer dates”. That is, I don’t need to be reminded to buy Halloween candy when it’s nearly Christmas time. I don’t even want to see that on my action list because it clutters up both my list and my thinking. Second, you can set OmniFocus to repeat an action a certain amount of time after that action’s completion date, not only its due date. “Pay the electric bill” needs to happen at the same time each month, but “make a haircut appointment” should happen a few weeks after my last haircut, whenever that was. Finally, OmniFocus’s project options like “complete with last action” are unmatched. Mix in many less crucial but nice-to-have features like nested tags, and per-tag location reminders, and it’s too good to walk away from.

I started moving my actions back out of Reminders and into OmniFocus and switched to using the OF 4 beta on my iPhone and iPad. That beta is turning into what I’d hoped OmniFocus would become: a stunning app that’s a pleasure to use. If it follows this current path, and OmniFocus 4 for Mac follows soon after, I think it’ll be amazing.

I’m glad I tried this experiment, and if nothing else it forced me to deeply review all of my actions before copying them from one system into another. Apple should be proud of Reminders and I bet it does everything most people need. It’s not (yet) enough for me, though. Until then, OmniFocus, I’m back.

Unusual shipping fail from Apple

I ordered a couple of Apple AirTags and keychain holders this weekend, and UPS dropped the package off on my doorstep a few minutes ago. The outer box had not been sealed in any way — no glue, tape, or anything:

Unsealed box from Apple

The packages inside were bent on arrival, likely from the warehouse:

Inner boxes were damaged in packing

I hope this is an exception. If I were a new Apple customer, I’d be unimpressed with their vaunted first impression.

Uniquely bad identity branding

My company has an account with a certain identity provider so we can test that our single sign-on feature works. Today one of my coworkers asked for an account with the IdP before he started working on that part of our code. I tried to create his user but got an error that the “username must be unique”. Huh. I double-checked our user list to ensure we didn’t have an account for him. We didn’t. I tried again and got the same error. That’s when I reached out to their support. They quickly replied:

To resolve this issue, please navigate to Administration > Settings > Branding and toggle the custom branding switch to green. Then try to create a user and it should allow you!

What. This had nothing to do with branding, and the switch in question looks like this:

"Custom branding" checkbox

But alright, I figured I’d try their suggestion.

It worked.

I supposed what likely happened was that support quickly found and fixed and issue, then gave me a switch to flip to make it feel like I was fixing something. I replied to them:

So we couldn’t add that user (but could add other users) because we didn’t have custom branding enabled? That can’t be right.

Their response?

It could be possible that the same username could exist in another customer’s tenant. So, once you enable the custom branding it would only look for your tenant for a unique username. With branding currently being disabled, the system is considering all tenants.

In short, if you click a logo to use your own theme for their site, usernames only have to be unique within your organization. If you don’t customize the site’s theme, they have to be unique across the whole identity provider. Furthermore, that uniqueness check only happens when you create a new user. If you flip the branding/namespace switch on, create an account, then flip the switch back off, the account is still active and usable even though it’s not globally unique. Even if you think that tying branding to uniqueness is a good idea — and it’s not — it doesn’t even work.

That whole setup is nuts.

Can't hire? Pay more.

Many recent news stories feature companies having a hard time hiring workers. In capitalism, this means one thing: they’re not paying enough. Period. It’s that simple.

The law of supply and demand says that if demand for a resource outstrips its supply, then price for that resource increases. If a buyer wants to purchase that resource, they have to pay more to compete with the other people who want to buy it. That’s one of the defining features of a free market, and it’s unreasonable to complain that no one is selling at the price they’d like to pay.

There are things that increase the supply of people willing to work for a company, thus lowering the price it can expect to pay, such as offering excellent benefits or earning a reputation as a wonderful employer. Those are forms of compensation that potential employees can and will consider. Conversely, having a reputation as a bad employer decreases the supply. I could name companies that would have to pay me more than I’d be worth to them before I’d even think of working for for them.

Either way, the market — in this case, the other employers competing to hire workers — sets the price of the resource. If a company can’t hire, they need to pay more. The labor market has determined that their current combination of pay and benefits isn’t good enough to attract new employees.

In other words, stop complaining and crack open that wallet.

Wisdom of the ages

The iOS App Store recommended that I check out a meditation app named “Calm”, featuring “Wisdom from Shawn and Camila”. Shawn is 22 years old; Camila is 24.

"Wisdom from Shawn and Camila", 2 people in their very early 20s

With due respect, Apple, I’m not expecting a lot of wisdom from a couple younger than the sweater I’m wearing.

There are many wonderful things youth can bring. Experience of a life long-lived is not one of them. I don’t want to sound curmudgeonly, but they’re 22 and 24, and I expect they’ll have little to offer on mid-career thoughts, or watching one’s parents grow older, or coming to grips with mortality. Like, the guy’s been quarantined for the majority of the time it’s been legal for him to drink.

"At a Crucial Juncture, Trump's Legal Defense Is Largely a One-Man Operation"

At a Crucial Juncture, Trump’s Legal Defense Is Largely a One-Man Operation — The New York Times

Highlights:

Joseph diGenova, a longtime Washington lawyer who has pushed theories on Fox News that the F.B.I. made up evidence against Mr. Trump, left the team on Sunday. He had been hired last Monday, three days before the head of the president’s personal legal team, John Dowd, quit after determining that the president was not listening to his advice.”

Also:

“Mr. Dowd had concluded that there was no upside and that the president, who often does not tell the truth, could increase his legal exposure if his answers were not accurate.”

Jokes about “the best people” aside, it sounds like genuinely competent people want nothing to do with the fiasco in DC.

Traveling with OmniFocus and OmniOutliner

I don’t travel a lot, so when I do I invariably find that I’ve forgotten something important (9 PM the night before: “say, dear, where are we boarding the dogs?” “I thought you were doing that!”). I wrote an AppleScript to copy items from an OmniOutliner document to an OmniFocus project so that I never have to forget again.

I love OmniFocus. It runs my life. But it lacks any kind of a template systems to let you quickly churn out copies of a project. That’s exactly what I needed here, though. Fortunately OmniOutliner fills that gap and gives me a nice way to describe that project. Here’s how mine starts:

List of things I want to remember

When I run the AppleScript and say “I want to travel on June 24”, it creates actions like “Call the vet to make pet boarding arrangements, with the Phone context, due on June 3 at 5PM”. I add everything to this list:

  • USB gadgets to charge
  • Toiletries to pack
  • Things to remove from my messenger bag (so I don’t find myself in line at security and realize I’ve still got my pocket knife)
  • People to notify, such as telling my credit union that I’ll be using my debit card in some exotic place like Topeka and please not to block it as fraud

A magic moment for me was hearing Merlin Mann’s suggestion to add an “update this list” action:

Reminder to update the list

A couple of days into my trip, I get a reminder to add anything new I’d forgotten or wish I’d done differently. This turns my template into a living document of exactly my own personalized requirements.

Purge your Yahoo account (but don't delete it!)

There are about 1.5 billion reasons to want to cancel your Yahoo account. Don’t do that!

According to Yahoo’s account deletion page, they “may allow other users to sign up for and use your current Yahoo! ID and profile names after your account has been deleted”:

Yahoo! account reuse

This is a terrible policy not shared by other service providers, and there are many scenarios where it’s a huge security problem for Yahoo’s users. For example:

  • You register for Facebook with your me@yahoo.com email address.
  • You forget about that, read about the newest Yahoo user database hack, and delete your Yahoo account.
  • A month later, someone else signs up to get your me@yahoo.com email address. They use Facebook’s password reset mechanism to take control of your account, download your private photos, and say nasty things to your friends.
  • Oh, and anyone you forgot to share your new address with is still sending personal communications to your old Yahoo address, and its new owner is reading them.

Here’s what you should do instead:

Purge your Yahoo account

It’s time to move on. Yahoo has a terrible security track record and shows no signs of improving.

First, understand what you’ll be doing here. You’ll be removing everything from your Yahoo account: your email, contacts, events, and so on. Permanently. There’s no changing your mind. It’s extreme, sure, but until you do it’s likely that hackers can:

  • Read messages from your spouse or partner.
  • See your calendar events to know when you’ll be away from the house.
  • Take over your account and start resetting every password associated with it, like Facebook, Amazon, and your bank.

Don’t delete your account. Clean it out!

Secure it

Before doing anything else, change your Yahoo password! Hackers probably have your current one. I’m not exaggerating.

Once that’s done, turn on two-factor authentication (2FA). This can prevent hackers from accessing your account even if they get your password.

Once that’s done, make a note to yourself to turn on 2FA for every other account you have that supports it.

Make your new home

Before you start, you’ll want to create an email account with a new provider. Lots of people like Gmail but pick one that looks good to you. This will be your new home account on the Internet: the email address that you give out to friends and coworkers and that you use to log into websites.

Clear your email

  • Log into your Yahoo mail.
  • Click the little checkbox above your emails to select all of them.
  • Click the Delete button to delete all email on that page. If you have lots of messages, you may have to repeat this several times.
  • Hover over the Trash mailbox to make the trashcan icon appear. Click the trashcan.
Trash icon
  • Confirm that you want to empty your trash.
Confirm emptying trash

Clear everything else

If you’re like most people, that’s probably 99% of your Yahoo data. You’re not quite done yet, though! Now click through each of the services in the little icons in the top left corner:

Other services to clear

They all may have more information stored in them. Each works a little differently but you should be able to figure out how to clean out each one.

Set a vacation reminder

Other email providers make it easy to forward all of your incoming mail to a new account. Yahoo removed that feature recently so you can’t use that convenient approach. Instead, you’ll make a Vacation Response to tell people about your new address.

  • Click the settings gear in the top right corner.
  • Choose Settings, then Vacation Response.
  • Check the box to “Enable automatic response”, and set the Until: year to as far in the future as it will let you.
Example vacation reminder
  • Enter a message like:

I may now be reached at me@example.com. Please update your address book. Thanks!

  • Click Save.

Now anyone writing to you will get a message with your new address, but their email will still land in your Yahoo inbox.

Change your logins

Now go through your web accounts and change all of them where you log in with me@yahoo.com to use your new email address instead. If you use a password manager to keep track of your accounts, this will be easy. Time consuming — thanks, Yahoo! — but easy.

Check back

You’re going to miss a few accounts, and some friends or family will stubbornly insist on sending email to your old address. Set a reminder or mark your calendar to check your Yahoo mail a month from now to see who’s written to you. Update each of those people or accounts, then delete all of your new messages. Check again in another month and then another after that. Eventually this will slow to a trickle and you can forget about your old Yahoo account for many months at a time (or until the next news article about a giant Yahoo hack comes along, and then you can smile to yourself because it doesn’t affect you anymore).

Conclusion

Migrating off Yahoo is a pain in the neck. Google, in contrast, makes it easy to extract all your information and then securely close your account. Yahoo does not. It won’t be quick or painless, but I recommend that you start now.