Upon my shoulder http://www.uponmyshoulder.com/blog // TODO: insert witty tagline Tue, 20 Jun 2017 20:25:30 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.10 Apple Contact & Calendar Server – dockerised http://www.uponmyshoulder.com/blog/2017/apple-contact-calendar-server-dockerised/ http://www.uponmyshoulder.com/blog/2017/apple-contact-calendar-server-dockerised/#comments Tue, 20 Jun 2017 20:25:30 +0000 http://www.uponmyshoulder.com/blog/?p=682 Continue reading Apple Contact & Calendar Server – dockerised]]> I’ve been using Radicale as a contacts / calendar server (CardDAV / DalDAV) for some time now, and it worked flawlessly across macOS and Windows Phone for contacts and calendars.

However, I recently got an iPhone and synchronising calendars from Radicale just crashed the iPhone calendar app. It worked fine some of the time, but most times it just crashed, which is not great.

Therefore, I went on the search for a better self-hosted calendaring server. Onwards! To the internets! Who promptly gave me a list of great self-hosted calendaring software.

Off that list, I tried to install Baikal, but the claimed Docker installation is broken by default: the container fails to build. The Dockerfile is pretty messy and complex, and as I’d rather not rely on PHP (it’s probably not the best filter, but… you know… PHP1), I gave up on it and looked into CalendarServer instead.

CalendarServer is an Apple open-source project providing calendar and contacts, written in Python under the Apache licence. The software is still regularly updated (the 9.1 release dates from last month), backed by a huge corporation, and from the looks of it should sync with iPhone and macOS pretty easily :)

Unfortunately, the docs are a bit sparse, but the install script was a great starting point to write up a Dockerfile. In the end, the whole Dockerfile is little more than apt-get installing all the dependencies and running the setup script.

Pretty helpful: this container, thanks to the built-in scripts, embeds all its external dependencies and runs Postgres and memcached. As long as you mount the data folder as a volume, you’re good to go with a completely contained calendar/contacts server that saves up to a single folder!

The server refuses to start as root though, which is a bit annoying given that Docker volumes cannot be edited by a non-root user… That is, unless you give that user a specific UID, and you make sure to give this UID ownership on the volume on the Docker host. A bit hacky, but works fine.

As an example of how to run it, here is the systemd unit file I use to run the server:

You’ll have to create that /opt/ccs/data folder yourself, and also create the config and user list as described in the QuickStart guide.

The code is on GitHub, and the built container is available on the Docker Hub.

Sync with iPhone and macOS has been absolutely faultless so far, so I’m pretty happy with it!

 

 

1: slightly ironic given this blog is WordPress, but nvm.

]]>
http://www.uponmyshoulder.com/blog/2017/apple-contact-calendar-server-dockerised/feed/ 2
Security & convenience http://www.uponmyshoulder.com/blog/2016/security-convenience/ http://www.uponmyshoulder.com/blog/2016/security-convenience/#respond Sat, 09 Jul 2016 12:41:24 +0000 http://www.uponmyshoulder.com/blog/?p=671 Continue reading Security & convenience]]> Last week I needed to change my defective French SIM card, from Free (who as an aside are an awesome ISP and equally good mobile provider). I happened to be in Paris so I decided to go to the Free shop, as I thought it’d be easier then getting a new SIM card send to my address on file (my parent’s address in France) given I now live in the UK.

When I got to the counter, I was met by a friendly enough Free guy (let’s call him A.) who told me it was no problem, I just needed my Free login and password and we’d be on our way. Cool! Adhering to password Best Practice™, I store all my credentials in Lastpass, so I just had to login into Lastpass to get my stuff and go.

Now, being also mindful that having one big repo of passwords is valuable and high-risk, I have 2FA on this account with a Yubikey, so I can’t access it from e.g. my phone.

I didn’t have my laptop on me, but my fiancé did, so we tried to use hers to access Lastpass, tethered to her phone. Being secure and all, Lastpass realised this attempt came from a “new location” and asked me to confirm it was me by sending a code by email. Email which I couldn’t access from my phone, because, hey, SIM card’s broken.

Now thankfully, I keep my email password separate from Lastpass and do remember it, so I could just log into Gmail on the laptop and get that code!

But email is also a very valuable target, the backdoor to your systems used by password recovery mechanisms, so I have 2FA there as well! Instead of my Yubikey, I use Google Authenticator to provide TOTP (more factors, more good, right?). TOTP which sadly failed mysteriously — I realised later on that removing the battery to take the SIM card out had reset the date and time to factory settings, which breaks the Time in Time-based One-Time Password.

Thankfully, at this point A. took pity of me and told me he shouldn’t, but he could let me use the employee wifi to get the email from my phone (already authenticated = no 2FA), which could get the lastpass code, which could get the Free credentials. Success! My random 30-chars password was finally here.

When seeing the password, A. went a bit blank. “Oh… You’ve changed it”, he said – well yes, why? Because this password needs to be entered through a clunky touch-based interface on the kiosk. Five minutes and three tries later, and my new SIM card was finally here.

Next time, I’ll do it online.

]]>
http://www.uponmyshoulder.com/blog/2016/security-convenience/feed/ 0
OVH: Database quota exceeded http://www.uponmyshoulder.com/blog/2015/ovh-database-quota-exceeded/ http://www.uponmyshoulder.com/blog/2015/ovh-database-quota-exceeded/#comments Sun, 22 Nov 2015 10:17:29 +0000 http://www.uponmyshoulder.com/blog/?p=661 Continue reading OVH: Database quota exceeded]]> OVH emailed me a few weeks back telling me that my shared database for the plan that powers uponmyshoulder.com was approaching its (huge!) quota of 25MB, and then again last week to tell me that this time, the quota was reached.

Once you reach the quota, the DB is placed in read-only mode, although SQL `DELETE` commands do go through correctly, as we’ll see later.

So my first instinct was to see what was wrong, by going into the PhpMyAdmin that OVH gives to each shared DB owner. It confirmed that the database was too big, mainly because of two tables: the main culprit at 9MB was wp_comments, the comments on this blog, and the second one at 5MB was its related sibling wp_commentmeta. The root cause being, of course, spam: all these comments were properly intercepted and classified as spam by Akismet, but as long as I didn’t purge them, they were still taking valuable disk space.

So I thought I could just delete the comments that Akismet marked as spam (as that info is available directly in the table) and go on with my day, but unfortunately no – the deletion went through, but the table was still marked as being 9MB, including about 7MB of “overhead“. How do we reclaim this overhead? By running OPTIMIZE TABLE… Which we cannot do as we’re in read-only mode.

At this point, I took a dump of the database, and deleted it through the OVH admin interface, recreated a new database and reimported that dump: solved! The new DB clocked at about 14MB, enough for the foreseeable future.

Lesson learned: clean your spam.

(PS: in the few days that passed between the db clean and me writing this article, I got another 355 spam comments. Yay.)

]]>
http://www.uponmyshoulder.com/blog/2015/ovh-database-quota-exceeded/feed/ 1
“They use some weird padding…” http://www.uponmyshoulder.com/blog/2015/they-use-some-weird-padding/ http://www.uponmyshoulder.com/blog/2015/they-use-some-weird-padding/#respond Fri, 13 Nov 2015 22:02:40 +0000 http://www.uponmyshoulder.com/blog/?p=658 Continue reading “They use some weird padding…”]]> A few days ago, a colleague was telling me about a project where she needs to implement a crypto scheme from an external vendor in order to talk to their API over HTTP. For complicated (and probably wrong) reasons, they decided to eschew TLS and develop their own system instead, relying on DES –not even triple DES! Basic DES, the one from the ’70s that is horribly insecure today– and RC4, which isn’t great either.

The whole scheme was bad, but my colleague added “and they also use that strange padding scheme – because the plaintext length needs to be a multiple of 8 bytes, at the end of every message, they put seven “Bell” characters!”.

The bell character? That’s odd. I mean, it’s in ASCII, and not usually part of any plaintext, so it’s probably safe to use as padding, but… Wait a second – padding with strange characters, all the same? That rings a bell!

And indeed it does – it’s PKCS#7!

PKCS#7 is meant to pad a message until it reaches the next block boundary, to use with block ciphers. It works by appending n characters of ASCII value 0xn, and of course the ASCII codepoint of the bell character is 0x07!

“Oh, that explains a lot. Now I won’t have to add blank spaces until it reaches (x mod 8) + 1 bytes and pad with bell characters”, my colleague said. I guess that’s the danger when you’re given a bad scheme to implement: it’s harder to realise when they actually do something right.

(Hat’s up to the Matasano crypto challenges: despite doing only level 1 and 2 if the memory serves –it was a while back–, they’re super useful for these sort of cryptography basics.)

]]>
http://www.uponmyshoulder.com/blog/2015/they-use-some-weird-padding/feed/ 0
Updating a tiny Rails app from Rails 3.1 to Rails 4.2 http://www.uponmyshoulder.com/blog/2015/updating-a-tiny-rails-app-from-rails-3-1-to-rails-4-2/ http://www.uponmyshoulder.com/blog/2015/updating-a-tiny-rails-app-from-rails-3-1-to-rails-4-2/#comments Fri, 09 Oct 2015 01:54:18 +0000 http://www.uponmyshoulder.com/blog/?p=654 Continue reading Updating a tiny Rails app from Rails 3.1 to Rails 4.2]]> In 2011 I wrote a small Rails app in order to learn Ruby better and see what all the fuss was about – this was Antipodes, a website that shows you the antipodes of a given point or country/state using google maps.

I built it using the latest and greatest version of Rails available at the time, which was 3.2. It has since fell to various security issues and has been superseded by newest version, and is currently unsupported.

I’ve been aware of these limitations and decided not to carry on hosting on such an old version, so I just stopped the nginx instance that was powering it and left it aside.

Until now! I had some time to spare recently, so I decided to upgrade.

Updating to Rails 3.2

The railsguide documentation about upgrading suggests not to update straight to the latest version of Rails, but to do it by steps instead. The first one for me was to update from 3.1 to 3.2.

First up, let’s update our Gemfile to pick up on the new Rails version, and let’s dive in!

The first issue I ran into was that the :timestamps model field definition are now marked as NON NULL. I wasn’t actively using these, so I decided to remove them from the DB rather than fixing DB import code.

My next issue was that some gems would not install properly – I decided to use the newest version of Ruby available on the system, 2.2, and it was not happy at my Gemfile requiring ruby-debug19. Fair enough, let’s remove it.

My next problem didn’t come from Rails itself, but rather from the gem I used to generate Google Maps, Gmaps4Rails. It underwent a serious rewrite in the past 4 years and now needed very different code under the hood – no problem. It also allowed me to clean some of the .coffee files and make better use of the assets pipeline.

An lo, the website was running under Rails 3.2!

Upgrading to Rails 4.0

The next step was to upgrade to Rails 4.0. This was very straightforward, a quick change in the Gemfile and a change to route handling (match was retired in favour of using the actual HTTP verbs of the route being handled, e.g. get) made it work, and a couple of new config options silenced the deprecation warnings.

Upgrading to Rails 4.2

And finally, the upgrade from Rails 4.0 to Rails 4.2 was made through the Gemfile only, no update was needed on the code itself.

 

And here we are! Antipodes is now up to date with its dependencies, and waiting for a new nginx+passenger to run again (more on that soon!).

]]>
http://www.uponmyshoulder.com/blog/2015/updating-a-tiny-rails-app-from-rails-3-1-to-rails-4-2/feed/ 1
remaildr.com is back! http://www.uponmyshoulder.com/blog/2015/remaildr-com-is-back/ http://www.uponmyshoulder.com/blog/2015/remaildr-com-is-back/#respond Mon, 18 May 2015 11:33:14 +0000 http://www.uponmyshoulder.com/blog/?p=647 Continue reading remaildr.com is back!]]> So, remaildr.com had been in a pretty sorry state for a couple of months now, and I kept thinking I should go have a look into it and get to the bottom of the issue.

And the bottom of the issue was the 6000 spam emails sitting in the inbox, making the server crash at startup.

They’re now deleted, and everything is back up and happy. I’m currently thinking about different monitoring options, but given it’s all email-based, no solution that I know of seem overly practical to me. Any idea would be appreciated. :)

]]>
http://www.uponmyshoulder.com/blog/2015/remaildr-com-is-back/feed/ 0
http://www.uponmyshoulder.com/blog/2015/643/ http://www.uponmyshoulder.com/blog/2015/643/#respond Thu, 16 Apr 2015 07:52:55 +0000 http://www.uponmyshoulder.com/blog/?p=643 Continue reading ]]> “So, the tests sometimes fail inexplicably” is a sentence you probably hear pretty often if you’re running any type of full-stack, browser-driven integration tests over a large-enough code base, especially when customising on top of an existing product.

Today’s instance was puzzling at first – the tests would sometimes fail to log in at all. That is, open the login page, fill in the username and password, wait until the URL change and assert that we’re now on the dashboard – nope, failure. It happens about 5% of the time, breaks straight away (no timeout), but happens to seemingly random users as different points of testing.

Well, time to output some debug information. First, let’s see whether that “wait until URL change” logic is working properly by outputting the URL after it changed – yes, the URL has indeed changed, and is now back into the login page with a little ?error=true tacked to the end.

An error at login? Let’s check the username and password… No, they’re definitely correct. And the problem is intermittent anyway. Could it be the backend rejecting valid credentials every so often? I’d never heard of that happening, but who knows. Let’s keep that in mind and possibly come back to it later.

As an added debugging, I made the test output the values of the username and password field sbefore they get submitted, and now we’ve got something interesting – the values filled in aren’t the values we told Cucumber to fill in! Instead of e.g. “username” / “password“, the username is filled in and sent as “usernameassword” and the password as “p“.

Uh? Ah!

And lo and behold, the culprit is unmasked – as a useful convenience, the login page executes a tiny bit of Javascript on page load that sets the focus to the “username” field so that a user doesn’t have to click or tab through it, but can start typing straight away. And Cucumber+Phantom faithfully emulating a browser and executing the javascript on that page will run into a race condition in which it starts entering keystrokes into a field, only to get its focus stolen by javascript and writing the rest of the keystrokes into the other field.

And the bug was of course intermittent because it would only happen when Cucumber was writing the password concurrently with page load. Any time before that and the fields would be correct, any time after that and the fields would be just as correct.

 

Our solution? Watir::Wait.until { browser.username_field.focused? } before actually filling in the fields and logging in. Works like a charm!

]]>
http://www.uponmyshoulder.com/blog/2015/643/feed/ 0
In Maven, LESS is less http://www.uponmyshoulder.com/blog/2013/in-maven-less-is-less/ http://www.uponmyshoulder.com/blog/2013/in-maven-less-is-less/#comments Sat, 24 Aug 2013 03:51:50 +0000 http://www.uponmyshoulder.com/blog/?p=622 Continue reading In Maven, LESS is less]]> Sorry, this is a rant.

I was recently investigating Maven plugins for LESS compilation. The use-case is pretty run-of-the-mill (I think?): I want to be able to write a .less file anywhere in my project src/ folder and have Maven compile it to CSS in the corresponding folder in target/ at some point of the build pipeline.

I first looked into lesscss-maven-plugin, a short-and-sweet kind of tool that looks perfect if you have one (and *only one*) target folder for all of your CSS. Working on a large project including things such as separate templates and per-plugin CSS, this would not be working for us.

More reading and research lead me to Wro4j, Web Resources Optimization for Java. One understood the cryptic acronym, it sounds like the kind of all-encompassing tool that the Gods of Bandwidth and Simplicity would bestow upon us mere mortals provided we made the required server sacrifices. A noble idea, but after actually using the thing, it didn’t take me long to drop the religious metaphor.

Wro4j is a horrible mess. There’s absolutely no justification in any way, shape or form for the complexity involved in this plugin. As a perfect example of being too clever for its own good, Wro4j includes several parsers for the configuration file: an XML parser, a JSON parser, and for some reason a Groovy parser. Why you would need three different ways to configure a poor Maven plugin —which should get its configuration from the pom.xml anyway— is beyond me.
And the implementation is the most horrific part: when supplied with a config file, Wro4j will try all successive parsers (yes, even when the file extension is .xml(1)) on the file and end up with this absolutely undecipherable error message if parsing failed with each ‘Factory’. Which will happen when Wro4j doesn’t like your XML configuration file for some reason.

I ended up using a bash script to find .less files and call lessc on them. No it’s not portable, no it’s not “the maven way”, but at least it works and it’s maintainable.

 

1: it takes a special kind of crazy YAGNI-oblivious Java helicopter architect to consider that a Groovy file saved as ‘config.json’ should be a supported feature. In a Maven (which is so heavily XML-based) plugin of all places!

]]>
http://www.uponmyshoulder.com/blog/2013/in-maven-less-is-less/feed/ 1
Pushing bookmarklets to their limits http://www.uponmyshoulder.com/blog/2013/pushing-bookmarklets-to-their-limits/ http://www.uponmyshoulder.com/blog/2013/pushing-bookmarklets-to-their-limits/#comments Thu, 25 Jul 2013 03:44:12 +0000 http://www.uponmyshoulder.com/blog/?p=620 Continue reading Pushing bookmarklets to their limits]]> I recently had to implement a new functionality for an internal web application: a button to download a specially-formatted file. The right way to do it is, of course, to deploy server-side code generating the needed file in the backend and make it accessible to the user via the front-end. The application in question is an important company-wide production system and I was on a hurry, so I decided to go the Quick way rather than the Right way 1.

Luckily, all the necessary information to create the file turned out to be accessible on a single web page, which meant I could create a user-triggered script to gather it from this page.

There are several ways for a user to inject and run custom (as in non-server-provided) javascript on their machine, such as using a dev console or a dedicated tool like Greasemonkey. But the best balance between ease of development and —comparatively— good user-experience is bookmarklets.

A bookmarklet is an executable bookmark. In practice, rather than being a normal URI such as:

http://example.com

They are of the form:

javascript: /* arbitrary js code */

All a user has to do is to add the bookmarklet to the bookmarks bar or menu of their browser of choice, click on it whenever they want to run the specified snippet of code against the current page, and said snippet will be ran.

To come back to our problem, the task at hand was to gather information on the page and make it downloadable as a text file with a custom extension.

Gathering the information was the easy part — a few strategically-placed querySelectorAll and string wrangling gave me exactly what was needed. The tricky part turned out to be creating a file.

How indeed do you create a downloadable file when you have no access to a server to download it from?

As it turns out, there exists a little-known provision of HTML link tags (<a> — </a>) that allows for embedding files as base-64 encoded strings in the tag’s href element itself. We can control what goes into this tag through javascript, hence we can generate and embed the file on-the-fly!

The last roadblock was to initiate the download action automatically2, rather than requiring the user to click on the bookmarklet, then on a ‘Download’ link. One would think it’s just a matter of clicking the newly-created link. Yes, but… In javascript, creating a link element is one thing, but clicking it is another — Firefox and IE allow the straightforward link.click(), but Chrome has historically only allowed click() on input elements. We have to dig deeper then, and manually generate a mouse event and propagate it to the link element3.

The following bookmarklet is what I ended up using as a prototype. It extracts information from a page, generates a specifically-formatted file containing the information, and fires up the download window:

If you wish to use this code sample to do something similar, remember to strip off comments and delete linebreaks, as the bookmarklet must be on one line.

 

Footnotes

1: the prototype worked, but the use-case I imagined for it turned out to be quite far removed from the true need. I did end up going the Right way ;-), learning a bit in the process though.

2: Respectively presenting the Open with/Save as dialog (Firefox) and downloading the file directly (Chrome).

3: Hat tip to StackOverflow for this technique.

]]>
http://www.uponmyshoulder.com/blog/2013/pushing-bookmarklets-to-their-limits/feed/ 1
Simulating bad network conditions on Linux http://www.uponmyshoulder.com/blog/2013/simulating-bad-network-conditions-on-linux/ http://www.uponmyshoulder.com/blog/2013/simulating-bad-network-conditions-on-linux/#respond Thu, 04 Apr 2013 10:24:36 +0000 http://www.uponmyshoulder.com/blog/?p=615 Sometimes, your network is just too good.

Today I ran into this issue as I was testing an application running off a VM in the local network. Latency and bandwidth were excellent, as you’d expect, but nowhere near the conditions you’d encounter over the internet. Testing in these conditions is unrealistic and can lead to underestimating issues your users will experience with your app once it’s deployed.

So let’s change that and add artificial latency, bandwidth limitations, and even drop a few packets, using tc.

Just put the following script in /etc/init.d, modify the values to fit your needs, make it executable, and run /etc/init.d/traffic_shaping.sh start to degrade performance accordingly.

I originally found the script on top web hosts’ website, and added a few things. Props!

]]>
http://www.uponmyshoulder.com/blog/2013/simulating-bad-network-conditions-on-linux/feed/ 0