Radiac's Bloghttp://radiac.net/blog/Things about technology, mostly to do with the weben-gbFri, 13 Sep 2019 16:04:16 +0000Syntactic Sugar vs Maintainabilityhttp://radiac.net/blog/2019/09/syntactic-sugar-vs-maintainability/<p>I've just given a talk at PyCon UK, called <a href="/pycon2019/">Syntactic Sugar vs Maintainability</a>, looking at balancing helping your users at the cost of your sanity.</p> <p>The synopsis was:</p> <blockquote> <p>Is it ever worth committing coding sins for the greater good? We'll look at techniques which can make your code easier to use at the cost of being harder to maintain, and when the effort is worth the reward.</p> <p>There are plenty of ways in which you can use and abuse the power of python to make your library code easier for your users to work with. I'm going to talk you through some techniques to design clean and simple library interfaces for your users, and explain how they can make things both easier and harder at the same time.</p> <p>Using real world examples we'll touch on topics such as automatic registration using metaclasses; changing base classes at runtime to save your users a line of code; and the joys and pitfalls of monkey patching things which should probably never be monkey patched.</p> <p>By the end of the talk you'll know why doing these things is usually a bad idea, and why I think it's worth doing them anyway.</p> </blockquote> <p>I've also uploaded the <a href="/pycon2019/">slides and links to resources</a> - if you came to listen, thanks very much! And if you didn't, the video should be up soon.</p>Fri, 13 Sep 2019 16:04:16 +0000http://radiac.net/blog/2019/09/syntactic-sugar-vs-maintainability/Tagulous 0.13.0http://radiac.net/blog/2018/04/tagulous-0130/<p><a href="/projects/django-tagulous/">Tagulous</a> v0.13.0 is now available - it adds support for Django 1.11 and addresses several issues - see the <a href="/projects/django-tagulous/documentation/upgrading/#changelog">changelog</a> for full details.</p> <p>Note that to support for Django 1.11, the names of automatically generated tag models has had to change - they're no longer allowed to start with an underscore. There is a simple fix, but this version does therefore require additional upgrade steps - see the <a href="/projects/django-tagulous/documentation/upgrading/">upgrade notes</a> for more information.</p>Mon, 30 Apr 2018 19:04:57 +0000http://radiac.net/blog/2018/04/tagulous-0130/Tagulous 0.12.0 releasedhttp://radiac.net/blog/2017/02/tagulous-0-12-0-released/<p><a href="/projects/django-tagulous/">Tagulous</a> v0.12 is now available - it adds support for Django 1.10 and addresses several issues - see the <a href="/projects/django-tagulous/documentation/upgrading/#changelog">changelog</a> for full details.</p> <p>Note that this version may require additional upgrade steps - see the <a href="/projects/django-tagulous/documentation/upgrading/">upgrade notes</a> for more information.</p>Sun, 26 Feb 2017 18:58:18 +0000http://radiac.net/blog/2017/02/tagulous-0-12-0-released/Mara - a Python network service frameworkhttp://radiac.net/blog/2015/12/mara-python-network-service-framework/<p>I've released a new version of <a href="/projects/mara/">Mara</a>, my network service framework written in Python. It aims to make it easy to build TCP/IP services, such as echo servers, flash policy servers, chatrooms, talkers and MUDs.</p> <p>It's event-based; that is to say you write event listener functions which you bind to events that your service raises - like <code>Connect</code>, <code>Receive</code> or <code>Disconnect</code>.</p> <p>Mara is on pypi, so you can <code>pip install mara</code>, then start writing your service. An echo server in Mara looks like this:</p> <pre><code>from mara import Service service = Service() @service.listen(mara.events.Receive) def receive(event): event.client.write(event.data) if __name__ == '__main__': service.run()</code></pre> <p>You can then save it as <code>echo.py</code> and run the service by calling it:</p> <pre><code>python echo.py * Server listening on</code></pre> <p>That's a pretty simple example, but Mara can do a bunch more. Its core has support for things like telnet negotiation, timers, a storage system, and seamless restarts (where client connections and storage objects persist, but your code is reloaded cleanly), and it ships with a <code>contrib</code> module which has a lot of optional extras, such as a command manager and dispatcher, basic natural language tools, user accounts and rooms.</p> <p>Although there's a focus on talkers and muds in the contrib modules at the moment, Mara should be a reasonable base for writing any network service. To get a feel for what you can do with it, take a look at the <a href="https://github.com/radiac/mara/tree/master/examples">examples</a>, which include an IRC-style chat server, a simple talker, and the start of a basic mud. There's also fairly comprehensive <a href="/projects/mara/documentation/">documentation</a>.</p> <p>I've always enjoyed writing this sort of thing, so this is a fun side project for me. At its heart Mara is a rewrite of my old perl chat server Cletus, which I wrote in <a href="/personal/diary/2001/10/id-240/">2001</a> - in fact if you dive back a few months through git, you'll see Mara was called Cletus until I realised that name was taken on pypi.</p> <p>It's still missing a few glaringly obvious features at the moment - most notably unicode and python 3 support, an example of using threads through events and timers, and more contrib modules for the mud like items, combat and NPCs. That said, it should make a solid starting point for any network service that you'd want to write, and as always, <a href="/projects/mara/documentation/contributing/">contributions are welcome</a>.</p>Sun, 13 Dec 2015 13:34:44 +0000http://radiac.net/blog/2015/12/mara-python-network-service-framework/Introducing Taguloushttp://radiac.net/blog/2015/10/introducing-tagulous/<p><a href="/projects/django-tagulous/">Tagulous</a> is a tagging library for Django which is based on <code>ManyToManyField</code> and <code>ForeignKey</code> relationships. I've been developing and using it internally for several years, and have recently tidied it up for release; it supports Django 1.4 to 1.9a, on Python 2.7 to 3.5.</p> <p>It started with a simple enough idea - rather than use generic relations like other tagging libraries, use a subclass of <code>ManyToManyField</code> which supports assignment using tag strings, to allow things like this:</p> <pre><code>class Person(models.Model): name = models.CharField(max_length=255) skills = TagField() person = Person.objects.create(name='Bob', skills='run, jump') person.skills = 'run, &quot;kung fu&quot;, jump'</code></pre> <p>And because the underlying relationship is a <code>ManyToManyField</code>, you can build queries exactly as you would expect:</p> <pre><code>runners = Person.objects.filter(skills='run') user_skills = Pet.skills.tag_model.objects.filter(pet__owner=request.user)</code></pre> <p>In this example the related tag model is generated automatically (and accessible on <code>field.tag_model</code>), but you can create custom tag models and share them between fields if you prefer. See the <a href="/projects/django-tagulous/documentation/usage/">usage examples</a> for more examples of how you can use Tagulous.</p> <p>The first version wasn't particularly complex, but as I started using it more it quickly became a more substantial project, with admin support, integrated autocomplete, support for hierarchical trees, and a <code>ForeignKey</code> version - a <code>SingleTagField</code> which essentially operates as a <code>CharField</code> with a list of <code>choices</code> which can be customised by users at runtime.</p> <p>It has a comprehensive set of tests, and has been in use for several years on several projects, so I'm reasonably confident that it's stable and the API won't need to be changed significantly now. That said, I'm releasing it as a beta version until it's been out in the wild for a bit - so please give it a try, and let me know how you get on.</p> <p>Tagulous is available on <a href="https://pypi.python.org/pypi/django-tagulous">pypi</a> and <a href="https://github.com/radiac/django-tagulous/">github</a>, and this site hosts the <a href="/projects/django-tagulous/documentation/">documentation</a> and a <a href="/projects/django-tagulous/demo/">demo</a> of the front-end.</p>Fri, 09 Oct 2015 07:22:53 +0000http://radiac.net/blog/2015/10/introducing-tagulous/A Tiny Web Font Loaderhttp://radiac.net/blog/2015/09/tiny-web-font-loader/<p>Today I'm releasing <a href="/projects/tinywfl/">TinyWFL</a>, my tiny web font loader which is about 95% smaller than other popular loaders.</p> <p>When web fonts started to gain adoption around 2010, the problem people had was <a href="http://www.paulirish.com/2009/fighting-the-font-face-fout/">FOUT</a> - the flash of unstyled text while you waited for the browser to download the font. I think most people would agree that this has since been solved very comprehensively by <a href="https://github.com/typekit/webfontloader">webfontloader</a> from Google and Typekit, and that it's now the de-facto standard loader - but back in 2010 or 2011 FOUT was still an issue, which is why I wrote my own.</p> <p>To be accurate, my loader doesn't actually load anything - it's more of a anti-FOUT aid. The idea behind avoiding FOUT is simple enough: characters are very rarely exactly the same size in different fonts, so if we put a few of them together in an HTML element and then measure its width we should get different values depending on which font it's using. If we measure the width for a font we know they'll have (ie a default font like <code>serif</code>), we can then compare that to the width of the web font we want to use; if they match, the web font hasn't loaded, so we use <code>setTimeout</code> to wait a bit, then we check again. Once we know they're loaded we can either fire off JavaScript functions, or set a CSS class somewhere which can be used by CSS rules to only show the font once it has loaded.</p> <p>This weekend I wanted to add a 2KB reduced character set font to a site, and thought about replacing my 5 year old code with webfontloader - but that's when I looked at the file sizes. The minified version of webfontloader that's currently on their git master is 11.5KB, and the version on Google's CDN is 16.6KB. Of course those sizes aren't huge, but a loader here and a polyfill there is how you end up with big slow pages. Besides, it seems silly to use a library that is 8x larger than the font it's trying to help show - at best it'll still be 50-100% of your average web font.</p> <p>By comparison TinyWFL is just 852 bytes. The reason it manages such a big difference is that it leaves out a bunch of features you won't need in most circumstances - and if you do need them, we've already got webfontloader.</p> <p>You can find <a href="https://github.com/radiac/tinywfl">TinyWFL on github</a></p> <p>As a reward for reading this far, have a couple of useful web font-related links:</p> <ul> <li><a href="http://www.fontsquirrel.com/tools/webfont-generator">Font Squirrel web font generator</a> - upload a font and they'll generate an excellent optimised web font for you to use with TinyWFL.</li> <li><a href="https://icomoon.io/app">IcoMoon app</a> - upload vector images (or pick from their selection) to generate an icon font. It probably doesn't make much sense to use TinyWFL for icon fonts, but it's still a great service.</li> </ul>Mon, 21 Sep 2015 09:51:12 +0000http://radiac.net/blog/2015/09/tiny-web-font-loader/Tips for SSL certificateshttp://radiac.net/blog/2015/05/ssl-certificate-tips/<p>Display CSR information:</p> <pre><code>openssl req -text -noout -in foo.csr</code></pre> <p>Display signed cert information:</p> <pre><code>openssl x509 -in foo.crt.pem -noout -text</code></pre> <p>To remove a password from a key:</p> <pre><code>openssl rsa -in foo.key.pem -out foo-unlocked.key.pem</code></pre> <p>To decode a CRL:</p> <pre><code>openssl crl -text -in ca.crl.pem</code></pre> <p>To check a certificate against a CRL:</p> <pre><code>cat ca/ca.crl.pem ca/ca.crt.pem &gt; crl-check.pem openssl verify -CAfile crl-check.pem -crl_check foo.crt.pem</code></pre>Mon, 18 May 2015 12:27:29 +0000http://radiac.net/blog/2015/05/ssl-certificate-tips/Self-Signing Certificate Authoritieshttp://radiac.net/blog/2015/05/self-ca/<h2 id="">Introduction</h2> <p>If you run a website which receives or displays personal information, passwords or other secrets, you need to encrypt your connections using SSL or TLS. This is what puts the &quot;S&quot; into HTTPS, FTPS, IMAPS, POPS etc, and requires private keys and public certificates. Your browser (or other SSL/TLS client) trusts certain CAs (certificate authorities), and they in turn are willing to trust you by issuing you a certificate, if you throw money at them.</p> <p>This is necessary for public-facing production deployments, and these days the cheapest certificates don't cost the earth - for example, Namecheap's <a href="https://www.namecheap.com/security/ssl-certificates.aspx?aff=86027">start at £6/$9</a>, and <a href="https://letsencrypt.org/">Let's Encrypt</a> should also be launching this summer, providing free domain-validated certificates. However, cheap certificates are <em>domain validated</em>, where the CA checks that you own the domain using automated tests; these can be slow and laborious, so it's often not practical or possible to get these for internal services or development environments.</p> <p>The alternative is to set yourself up as a self-signing CA. You won't be trusted by the public, but it's a good option if you're in the position where you're not public-facing, or where you can tell your users to install your root CA before they use your service. You'll be able to issue as many certificates as you want, and your connection should be just as secure as with a &quot;proper&quot; certificate.</p> <h2 id="">The easy way</h2> <p>I've written <a href="/projects/caman/">caman</a> which will do everything for you - it's a bash script with all the commands I'm about to describe in excruciating detail, so if all you want to do is jump to getting your certificates, go over to the project page and start following its instructions.</p> <aside class="download"> <p><a href="/projects/caman/">Get caman</a>, the easy self-signed certificate authority manager</p> </aside> <p>Read on if you want to know how to do it yourself.</p> <h2 id="">What we're aiming for</h2> <p>We're going to create a directory which contains your CA, your host keys, and the certificates you generate. The structure will be:</p> <pre><code>ca/ Your CA information caconfig.cnf CA configuration (modify this) ca.key.pem CA private key (keep this safe) ca.crt.pem CA public certificate (distribute this) ca.crl.pem List of revoked keys (publish this) serial Next serial number index.txt Registered certificates crlnumber Next CRL number newcerts/ A copy of each certificate signed store/ Your certificates host.domain.tld/ One folder per host config.cnf Config for the given host YYYY-MM-DD/ Build date for cert set host.domain.tld.key.pem Key host.domain.tld.csr Signing request host.domain.tld.crt.pem Certificate host.domain.tld.keycrt.pem Key + cert combo</code></pre> <h2 id="">Prepare your CA</h2> <p>Before we start, you'll need <code>openssl</code> to be installed on your system. In Ubuntu, that would be:</p> <pre><code>sudo apt-get install openssl</code></pre> <p>Now we'll create the CA dir, and start the serial number at 1:</p> <pre><code>cd my_ca mkdir ca store mkdir ca/certs ca/private echo '01' &gt; ca/serial touch ca/index.txt</code></pre> <p>You will now need to create your <code>ca/caconfig.cnf</code> file. You can use the caman template:</p> <pre><code>curl https://raw.githubusercontent.com/radiac/caman/master/ca/caconfig.cnf.default &gt; ca/caconfig.cnf</code></pre> <p>You will need to change some lines - look for the comments starting <code># &gt;&gt;</code>. </p> <ul> <li> <p>Change the 6 values under <code>[ req_distinguished_name ]</code>:</p> <ul> <li><code>countryName</code>: your two-character country code</li> <li><code>stateOrProvinceName</code>: your state or province</li> <li><code>organizationName</code>: the name of your organisation</li> <li><code>organizationUnitName</code>: your department in the organisation</li> <li><code>commonName</code>: the name of your organisation</li> <li><code>emailAddress</code>: your e-mail address</li> </ul> </li> <li> <p>Change the CRL distribution points URL under <code>[ usr_cert ]</code> and <code>[ v3_ca ]</code>:</p> <ul> <li><code>crlDistributionPoints</code>: URL where you will publish your <code>ca.crl.pem</code></li> <li>The CRL is a list of revoked certificates which you'll need to update each time you revoke a host certificate; if you don't want to be bothered with this, you can just comment these lines out, as well as <code>crl_extensions</code> and <code>crlnumber</code> under <code>[ CA_default ]</code>.</li> </ul> </li> <li>You can ignore the value for <code>default_days</code> here - caman uses it, but OpenSSL won't; we'll be passing it directly on the command line.</li> </ul> <h2 id="">Create the root certificate</h2> <p>Your CA is identified by its root certificate. First we need to create the private CA key:</p> <pre><code>openssl genrsa -aes256 -out ca/ca.key.pem 4096</code></pre> <p>The <code>openssl genrsa</code> command generates an RSA key, and the other options tell it to encrypt it with AES 256 (<code>-aes256</code>), to use 4096 bits, and to write it to the file <code>ca/ca.key.pem</code>.</p> <p>When you run the command, it will ask you for a password - keep it safe, you'll need it every time you want to generate and sign a new certificate.</p> <p>This will generate the private CA key, <code>ca/ca.key.pem</code>. This is important:</p> <ul> <li>Do not lose this key. Without it, certificates can't be signed or renewed</li> <li> <p>Do not disclose this key to anyone. If it is compromised, others will be able to impersonate the CA.</p> <aside class="idea"> <p>If you're really paranoid, you could take further steps to protect your key, by creating an intermediate authority to sign host certificates, and keeping your root key somewhere more secure, eg on a USB key locked in a safe; that way if your intermediate authority key is compromised, you could revoke it and create a new one, without having to get people to install your new CA certificate. However, we'll assume that's not an issue for you, and won't be using an intermediate authority here.</p> </aside> </li> </ul> <p>Now we can use the key to generate the public CA certificate:</p> <pre><code>openssl req -x509 -new -key ca/ca.key.pem -days 36500 -out ca/ca.crt.pem -config ca/caconfig.cnf</code></pre> <p>The <code>openssl req</code> command with <code>-x509</code> tells OpenSSL to generate a self-signed certificate; the other options tell it to generate a new certificate (<code>-new</code>) and how long the certificate should be valid for - in this case, <code>-days 36500</code> means about 100 years. It then uses the <code>caconfig.cnf</code> which we configured earlier, and puts the certificate in the file <code>ca/ca.crt.pem</code>.</p> <h2 id="">Publishing your CA Certificate and CRL</h2> <p>To get clients to trust certificates signed by the new self-signing authority, they must install the root certificate, <code>ca.crt.pem</code>.</p> <p>The easiest way to do this is to put it on your web server as a normal file for download, called <code>ca.crt</code>. Most browsers will know what to do with it from there.</p> <p>If you're using Apache to serve your page, it may need to know the MIME type - add this to your configuration or <code>.htaccess</code>:</p> <pre><code>AddType application/x-x509-ca-cert .crt</code></pre> <p>You can then generate your CRL with the following command:</p> <pre><code>openssl ca -gencrl -out ca/ca.crl.pem -config ca/caconfig.cnf</code></pre> <p>To publish it, just put it at the URL you defined in your <code>caconfig.cnf</code> above. Remember to update it each time you renew or revoke a certificate.</p> <h2 id="">Preparing for a new host</h2> <p>Before we start creating hosts, lets set up a directory to store them.</p> <p>In this article we'll be creating a certificate for <code>my.example.com</code>:</p> <pre><code>mkdir store/my.example.com</code></pre> <p>To make a wildcard certificate to cover multiple hosts, just use an asterisk - for example, <code>*.example.com</code> would catch any subdomain of example.com.</p> <p>You will now need to create a configuration for this host. Again, you can use the caman template:</p> <pre><code>curl https://raw.githubusercontent.com/radiac/caman/master/ca/host.cnf.default &gt; store/my.example.com/config.cnf</code></pre> <p>You will need to change some lines - look for the comments starting <code># &gt;&gt;</code>. </p> <ul> <li> <p>Change 4 of the values under <code>[ host_distinguished_name ]</code>:</p> <ul> <li><code>countryName</code>: the two-character country code for this host</li> <li><code>stateOrProvinceName</code>: the state or province for this host</li> <li><code>organizationName</code>: the name of the organisation for this host</li> <li><code>emailAddress</code>: the e-mail address for the admin for this host</li> <li>Do not change <code>commonName</code> or <code>organizationUnitName</code> - these are placeholders which will be set by caman</li> </ul> </li> <li>You can ignore the value for <code>default_days</code> here - caman uses it, but OpenSSL won't; we'll be passing it directly on the command line.</li> </ul> <p>You're now ready to make the certificate itself.</p> <h2 id="">Creating a host certificate</h2> <p>First create a new sub-directory to store this set of files - there will be a key, a CSR (certificate signing request) and a certificate. I like to use the date I'm generating the certificate:</p> <pre><code>mkdir store/my.example.com/2015-05-18</code></pre> <p>Now we'll create a new private key and CSR with this command:</p> <pre><code>openssl req -sha256 \ -newkey rsa:2048 -nodes \ -keyout store/my.example.com/2015-05-18/my.example.com.key.pem \ -new -out store/my.example.com/2015-05-18/my.example.com.csr \ -config store/my.example.com/config.cnf</code></pre> <p>This again calls <code>openssl req</code>, but without <code>-x509</code> this time because we don't want it to be self-signed - we want to sign it using our own CA. We then tell it to use SHA256 (<code>-sha256</code>), and generate a new 2048 bit RSA private key (<code>-newkey rsa:2048</code>) which is not encrypted (<code>-nodes</code> - that's &quot;no DES&quot;, not &quot;nodes&quot;) in the file ending <code>.key.pem</code>. It will then use this to create a new CSR (<code>-new</code>) in the file ending <code>.csr</code>. It uses the host config we created earlier to provide any additional settings.</p> <p>Next we need to sign the CSR to generate the certificate:</p> <pre><code>openssl ca \ -in store/my.example.com/2015-05-18/my.example.com.csr \ -out store/my.example.com/2015-05-18/my.example.com.crt.pem \ -days 3650 -config ca/caconfig.cnf</code></pre> <p>This calls <code>openssl ca</code> to use the certificate authority to sign the CSR (<code>-in</code>) and generate the certificate (<code>-out</code>). Here it will be valid for 3650 days (<code>-days</code>), or approximately 10 years. We give it the CA config this time, so it knows where to find all the settings for our CA.</p> <p>You will now have a private key ending <code>.key.pem</code>, and a public certificate ending <code>.crt.pem</code>. In most cases you'll use these separately, but some services may want them merged together in one file (such as Apache wth the <code>SSLCertificateFile</code> directive), so we'll concatenate them just in case it's needed:</p> <pre><code>cat store/my.example.com/2015-05-18/my.example.com.key.pem \ store/my.example.com/2015-05-18/my.example.com.crt.pem \ &gt; store/my.example.com/2015-05-18/my.example.com.keycrt.pem</code></pre> <p>You can now copy those three files to the server (you won't need the <code>.csr</code>) and configure your services to use them. That's a bit beyond the scope of this article, but may be something I'll follow up with in a later one.</p> <h2 id="">Revoking and renewing certificates</h2> <p>If a host's certificate has expired, is no longer needed, or has been compromised, you must revoke the current certificate for that host, and generate and publish a new CRL.</p> <p>First check <code>ca/index.txt</code> for the index corresponding to the host you're revoking:</p> <pre><code>more index.txt | grep my.example.com</code></pre> <p>You will see something like this:</p> <pre><code>R 250513123511Z 150516124528Z 01 unknown /C=CN/ST=State/O=MyOrg/OU=my.example.com/CN=my.example.com/emailAddress=email@example.com R 250513124545Z 150516124604Z 02 unknown /C=CN/ST=State/O=MyOrg/OU=my.example.com/CN=my.example.com/emailAddress=email@example.com V 250513124606Z 03 unknown /C=CN/ST=State/O=MyOrg/OU=my.example.com/CN=my.example.com/emailAddress=email@example.com</code></pre> <p>If a line starts with an <code>R</code> it means that certificate has been revoked; look for the one starting <code>V</code> with <code>CN=</code> which matches your host; it will almost certainly be the last one. Then take the short number in the fourth column; in the example above, the index is <code>03</code>.</p> <p>Now you have the index, you can revoke that certificate:</p> <pre><code>openssl ca -revoke ca/newcerts/03.pem&quot; -config ca/caconfig.cnf</code></pre> <p>replacing <code>03</code> with the index for that certificate.</p> <p>If you are replacing the certificate, you can now create a new host certificate exactly as you did in the <em>Creating a host certificate</em> section above.</p> <p>Don't forget to update and publish a new CRL, as described under <em>Publishing your CA Certificate and CRL</em>.</p>Mon, 18 May 2015 12:08:00 +0000http://radiac.net/blog/2015/05/self-ca/POODLEhttp://radiac.net/blog/2014/10/poodle/<p>I have been meaning to get back on the blogging horse for some time, and what better way than with a new SSL vulnerability.</p> <p><a href="http://googleonlinesecurity.blogspot.co.uk/2014/10/this-poodle-bites-exploiting-ssl-30.html">POODLE</a> was announced this morning. It's a 5/10 on the panic scale, but both users and sysadmins should take action now.</p> <p>This one isn't particularly exciting compared to the recent sky-is-falling <a href="http://heartbleed.com/">heartbleed</a> and <a href="http://en.wikipedia.org/wiki/Shellshock_%28software_bug%29">shellshock</a> - instead of giving away all your secrets and/or shell access to anyone with curl, the worst-case scenario with POODLE is that someone can read your SSL traffic; still bad, but for most people running small sites it's nowhere near the same scale.</p> <p>Unlike shellshock and heartbleed though, this doesn't look like something which is likely to be fixed by a distro patch any time soon, because this vulnerability is <a href="https://www.dfranke.us/posts/2014-10-14-how-poodle-happened.html">inherent in SSLv3</a> (I'm no crypto expert, so I won't attempt to explain it myself). Because it is still used in the wild, distros are unlikely to disable it by default in the immediate future, so sysadmins will need to do something about it themselves.</p> <p>This vulnerability doesn't come as a great surprise - SSLv3 is getting on a bit now, and was superseded by TLSv1 which has been supported by most browsers since IE6. However, most clients and servers are designed to fall back to earlier protocols if the newer ones fail - a good idea in theory, but in practice an attacker who wants you to use SSLv3 can force this to happen.</p> <p>While this fallback strategy is likely to be disabled in future distro patches using <a href="http://marc.info/?l=openssl-dev&m=141333049205629&w=2"><code>TLS_FALLBACK_SCSV</code></a>, it will still leave any use of SSLv3 vulnerable. Although Google is using SCSV for maximum compatibility, based on <a href="https://blog.cloudflare.com/sslv3-support-disabled-by-default-due-to-vulnerability/">Cloudflare's numbers</a> where a trivial amount of valid traffic actually uses SSLv3, most people seem to be advocating the removal of SSLv3 altogether.</p> <p>As a user you're vulnerable if you use SSLv3, so you should disable it - you're extremely unlikely to need it anyway. I won't go into details, but Mozilla will disable SSLv3 <a href="https://blog.mozilla.org/security/2014/10/14/the-poodle-attack-and-the-end-of-ssl-3-0/">in Firefox 34</a>, or you can disable it now in <code>about:config</code> by setting <code>security.tls.version.min == 1</code>.</p> <h3>Steps for sysadmins</h3> <p>Systems' traffic is vulnerable if they're running SSLv3, so a reasonable course of action would therefore be to disable SSLv3 at the top level of your server config, then re-enable it on specific sites if you get reports of problems - although it would be best to wait for a stable <code>TLS_FALLBACK_SCSV</code> patch to land before re-enabling it.</p> <p>Those running nginx can disable SSLv3 with <a href="https://github.com/cloudflare/sslconfig/blob/master/conf">Cloudflare's cipher configuration</a> (add to <code>http</code> or <code>server</code> context):</p> <pre><code>ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:EECDH+RC4:RSA+RC4:!MD5; ssl_prefer_server_ciphers on; </code></pre> <p>Apache users can add (to server or virtual host context):</p> <pre><code>SSLProtocol all -SSLv2 -SSLv3 </code></pre> <p>And dirty IIS users get what they deserve - a <a href="https://www.digicert.com/ssl-support/iis-disabling-ssl-v3.htm">17 step procedure</a> where you have to fiddle with the registry.</p> <p>You should of course also take a look at any other services which are likely to support SSLv3, like mail or VPNs.</p> <h3>Testing your connection</h3> <p>As with heartbleed, <a href="https://www.ssllabs.com/ssltest/">Qualys SSL Labs</a> seems to be the place to go for an easy and comprehensive assessment of your SSL security. Alternatively you could use openssl:</p> <pre><code>openssl s_client -connect [server]:[port] -ssl3 </code></pre> <p>If you run that command and connect successfully, you're still vulnerable.</p>Wed, 15 Oct 2014 07:45:59 +0000http://radiac.net/blog/2014/10/poodle/Canvas bezier curveshttp://radiac.net/blog/2013/12/canvas-bezier-curves/<p>The new Christmas design for this site uses bezier curves on canvas elements to generate random snowdrifts behind the header. Drawing a <a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">bezier curve</a> is pretty simple, so seems like a reasonable place to start my new blog. First you need a canvas and a context:</p> <pre><code class="language-html">&lt;canvas id=&quot;myCanvas&quot; width=&quot;400&quot; height="200"&gt;&lt;/canvas&gt; &lt;script&gt; var canvas = document.getElementById('myCanvas'), context = canvas.getContext("2d"); ; &lt;/script&gt; </code></pre> <aside class="code"> <h1>Think Turtles</h1> <p>A quick aside for those who haven't used the canvas before: a canvas element has a context property, which is what you draw on. Context methods to draw lines take destination coordinates, and draw them from the current position - think of <em>pen up</em> in Logo's <a href="http://en.wikipedia.org/wiki/Turtle_graphics">turtle graphics</a>, only with absolute positioning.</p> <p>The canvas equivalent of <em>pen up</em> is <code>context.moveTo(x, y)</code>, so to draw a line from <code>(50, 50)</code> to <code>(150, 50)</code>, you would say:</p> <pre><code class="language-js">context.beginPath(); context.moveTo(50, 50); context.lineTo(150, 50); c.strokeStyle = '#000'; c.stroke(); </code></pre> <p>You'll notice I added some extra bits there - <code>beginPath()</code> says we're starting a new path, and <code>stroke()</code> draws it using the current style. Call <code>beginPath()</code> whenever you're about to change the style.</p> </aside> <p>The canvas bezier curve takes 6 arguments; two sets of control points, and an end point:</p> <pre><code class="language-js">context.bezierCurveTo(c1x, c1y, c2x, c2y, ex, ey); </code></pre> <p>Here's an example:</p> <pre><code class="language-js">context.beginPath(); context.moveTo(50, 50); context.bezierCurveTo(50, 150, 250, 150, 350, 50); context.strokeStyle = '#00d'; context.stroke(); </code></pre> <canvas id="bezier-eg" width="400" height="200"></canvas> <script> $(function () { var c = $('#bezier-eg')[0].getContext("2d"), d = 3 ; // Guides function cross(x, y) { c.beginPath(); c.moveTo(x-d, y-d); c.lineTo(x+d, y+d); c.moveTo(x-d, y+d); c.lineTo(x+d, y-d); c.strokeStyle = '#d00'; c.stroke(); } c.beginPath(); c.moveTo(50, 50); c.lineTo(50, 150); c.moveTo(350, 50); c.lineTo(250, 150); c.strokeStyle = '#bbb'; c.stroke(); // The bezier line itself c.beginPath(); c.moveTo(50, 50); c.bezierCurveTo(50, 150, 250, 150, 350, 50); c.strokeStyle = '#00d'; c.stroke(); // Markers c.font="10px Arial"; cross(50, 50); c.fillText("(50, 50)", 35, 35); cross(350, 50); c.fillText("(350, 50)", 335, 35); cross(50, 150); c.fillText("(50, 150)", 35, 165); cross(250, 150); c.fillText("(250, 150)", 235, 165); }); </script> <p>I've added some grey lines and red markers to show what's going on. First we <code>moveTo(50, 50)</code>, then call <code>bezierCurveTo</code> with the two control points <code>(50, 150)</code> and <code>(250, 150)</code>, and the end point <code>(350, 50)</code>. The result is a line from the current position to the end point, pulled out of place by the control points.</p> <p>Once you've got that far, building a randomly-generated snowdrift is trivial - a bit of <code>Math.random()</code>, and instead of <code>context.stroke()</code> use <code>context.fillStyle</code> and <code>context.fill()</code>.</p> <p>To finish the effect, I'm drawing two background snowdrifts on one canvas element, and a foreground snowdrift on a second, with snowflakes falling in between - although I cheated there and used an animated gif which I had rendered earlier. Your CPU thanks me.</p>Mon, 09 Dec 2013 11:42:11 +0000http://radiac.net/blog/2013/12/canvas-bezier-curves/TCMI 2.0http://radiac.net/blog/2013/12/tcmi-20/<p>I am very proud to announce my finest work to date - the Tacky Christmas Music Interface 2.0!</p> <p>The old TCMI played midi files, but most browsers seem to struggle with those these days, and even when it did work, modern soundfonts made the experience quite variable. To get around this, the new version of TCMI now uses HTML5 audio to play MP3 or OGG files (depending on browser support).</p> <p>This also means that if you've got the relevant PPL/PRS license, you can now play non-tacky music to your visitors! Although I'm not quite sure what the point of that would be.</p> <p>The old version also ran in an iframe, which made front page SEO and deep-linking difficult for 1/12th of the year. This version therefore has the option to use AJAX loads and <code>history.pushState</code>, with the controls in a styleable <code>&lt;div&gt;</code> overlay.</p> <p>There's also a new cleaner design, but those who want a tacky UI to go with the tacky music can opt to use the classic design.</p> <p>You can find out more on the <a href="/projects/tcmi/">TCMI project page</a>, where you can also download some of the old TCMI midis which I've converted into MP3s and OGGs. Improvements welcome on <a href="https://github.com/radiac/tcmi">github</a>.</p>Tue, 03 Dec 2013 13:19:05 +0000http://radiac.net/blog/2013/12/tcmi-20/A New Bloghttp://radiac.net/blog/2013/12/new-blog/<p>Welcome to my new tech blog, where I'll be writing about programming, sysadmin and anything else related to computers that I think may be of general interest to strangers on the internet.</p> <p>I've been on the internet for about 16 years now, and I've had this site for almost 14 of them. I want to get back to sharing some of the stuff I'm working on, so this blog will be a mix of articles and tutorials covering various topics related to web development. I also want to learn things through this process too - as a freelance developer, I've spent a lot of the past 10 years working away on my own, and I'm sure I've missed some tricks - so please do send me feedback, either in the comments or through the <a href="/contact/">contact form</a>.</p> <p>For those who have been visiting my site for years, I'll still keep my <a href="/personal/diary/">personal diary</a> going, but from now on that will be where I ramble on about my cats, and things that annoy me which I can't fit into 140 characters on twitter.</p> <p>For those who are new, welcome, and I hope that you will find my blog useful.</p>Sun, 01 Dec 2013 01:15:00 +0000http://radiac.net/blog/2013/12/new-blog/