Jekyll2021-12-15T11:30:06+00:00https://www.rittme.com/feed.xmlRittme.comBernardo Rittmeyer personal blog. Here you can find some of my thoughts on software and life.
Another Summer at Mozilla: Password Manager2015-09-28T20:30:00+00:002015-09-28T20:30:00+00:00https://www.rittme.com/mozilla/firefox/password-manager/2015/09/28/firefox-password-manager-intro<p>Another summer went by and one more amazing internship reached it end. It’s that time again, when I talk about how was my internship and what I did during the summer.</p>
<p>During this summer I worked at the Firefox Password Manager Team. Our goal was to make the best password manager for the web, integrated into the Firefox Desktop and Mobile browsers.</p>
<h2 id="making-a-better-password-manager">Making a Better Password Manager</h2>
<p>Logging in is one the most common actions on the Web. Every web service you use require login credentials. Keeping tab of all your passwords isn’t easy.
People have different methods to cope with this. Some use the same password everywhere, some keep a file with all their passwords, while others use post-its around their screen. All of this is really bad for your security. Loose that single password you use everywhere and you will be in a lot of trouble.</p>
<p>A good password manager is supposed to store all your passwords securely, detect login pages and fill the forms automatically. Making heuristics that work reliably across the web is something complex, that deserves an entire post only about it.</p>
<p>For this post I would like to quickly go through what I did during this summer.</p>
<h2 id="ui-improvements">UI Improvements</h2>
<p>One of our main goals is to make the password manager more user friendly. Some of our interfaces didn’t really allow for users to have full control of the manager behavior.</p>
<h3 id="capture-popup">Capture popup</h3>
<p><img src="/images/in-content/sad-doorhanger.png" alt="Old password capture doorhanger" class="center-image" width="420px" />
This is probably the best example of lack of control. The user had only the choice to save the password or not save it (or never save, for that matter). But what password is this? Am I sure the browser got the right field? What do I do if I have a typo?</p>
<p><img src="/images/in-content/happy-doorhanger.png" alt="New password capture doorhanger" class="center-image" width="386px" />
With the new capture doorhanger, you can actually see the username and password that were captured. Both username and password fields are editable, so if you have a typo, or the wrong field was captured, you can fix it before saving.</p>
<h3 id="context-menu-fill">Context Menu Fill</h3>
<p>This one was supposed to be a fix for <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=433238">Bug 433238</a> which we could simplify as: the user don’t have an interface to select which login to fill if there is no username field.</p>
<p>We ended up with a nice interface in the context menu, which can be useful in many situations. Just right click your username to fill the login form, or right click you password if you only want to fill that field.</p>
<video width="528" height="394" class="center-image" autoplay="" loop="" preload="" muted="">
<source src="/images/in-content/menufill.mp4" type="video/mp4" />
![Context Menu Fill](/images/in-content/<menufill class="gif"></menufill>)
</video>
<h2 id="presentation">Presentation</h2>
<p>If you want to know more about what I did, take a look at my summer internship presentation bellow.</p>
<iframe class="center-image" src="/mozilla-2015/load.html" width="760" height="444" frameborder="0" allowfullscreen=""></iframe>
<p>Edit: Mozilla seems to have lost the presentation video, so I replaced it with the slides.</p>
<!-- ## The team ##
In this post I wanted to cover mostly the features I worked on. Check my post about __the Password Manager Team__ to have a full view of the project. -->Another summer went by and one more amazing internship reached it end. It’s that time again, when I talk about how was my internship and what I did during the summer.About Submiting Asynchronous Forms2014-10-01T20:00:00+00:002014-10-01T20:00:00+00:00https://www.rittme.com/webdev/javascript/firefox/ajax/2014/10/01/about-submiting-ajax-forms<p>I’ve seen some websites having problems with browsers autocompletion functions recently and I thought I should write something about it. My browser simply would not recognize some asynchronous form submissions and would not save my password. Like everyone else, I love my autocomplete and I don’t like who don’t let me use it.</p>
<p>Most popular browsers nowadays have quite smart form completion functionalities. Firefox, for example, came a long way by supporting forms created dynamically by Javascript. But I saw some websites completely disregarding the way you should implement a web form, breaking auto-complete in every browser there is.</p>
<p>The problems with these forms were they used anchor elements or images as submission buttons, using some code like the one bellow:</p>
<p>Let’s look at this asynchronous form:</p>
<p><strong>html</strong></p>
<figure class="highlight">
<pre><code class="language-html" data-lang="html"><span class="nt"><form</span> <span class="na">id=</span><span class="s">"login-form"</span><span class="nt">></span>
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">name=</span><span class="s">"username"</span><span class="nt">></span>
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"password"</span> <span class="na">name=</span><span class="s">"password"</span><span class="nt">></span>
<span class="nt"><a</span> <span class="na">id=</span><span class="s">"submit-button"</span><span class="nt">></span>Submit<span class="nt"></a></span>
<span class="nt"></form></span></code></pre>
</figure>
<p><strong>Javascript</strong></p>
<figure class="highlight">
<pre><code class="language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">formButton</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">submit-button</span><span class="dl">"</span><span class="p">);</span>
<span class="nx">formButton</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">click</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">evt</span><span class="p">){</span>
<span class="nx">evt</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
<span class="kd">var</span> <span class="nx">xhr</span> <span class="o">=</span> <span class="kd">var</span> <span class="nx">xhr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">();</span>
<span class="p">...</span>
<span class="p">});</span></code></pre>
</figure>
<p>This is a really bad idea. We have semantically correct elements to submit the form, namely <code class="language-plaintext highlighter-rouge"><button></code> and <code class="language-plaintext highlighter-rouge"><input type="submit"></code>, which should be used in these situations. Using the correct elements throughout your webpage is important for both your browser and indexers, as Google, to understand correctly what you mean. CSS is always there to help you make them look exactly the way you want.</p>
<p>So please, when writing your forms, or any part of a web page for that matter, please use the correct semantic element to do what you want.</p>I’ve seen some websites having problems with browsers autocompletion functions recently and I thought I should write something about it. My browser simply would not recognize some asynchronous form submissions and would not save my password. Like everyone else, I love my autocomplete and I don’t like who don’t let me use it.Mozilla Internship2014-09-20T10:00:00+00:002014-09-20T10:00:00+00:00https://www.rittme.com/mozilla/internship/2014/09/20/mozilla-internship<p>It’s more than time I should write something about my Mozilla Internship during this summer. Expect pictures and awesomeness.</p>
<p>Let’s start by explaining this a bit better. During the summer of 2014 I was an Intern at Mozilla San Francisco (and Mountain View), working with the Firefox Engineering Team.</p>
<p>I would love to share this experience with you, because I feel the need to spread the word about how fun and rewarding an internship like this one can be.</p>
<h3 id="the-city">The City</h3>
<p><img src="/images/in-content/golden-gate.jpg" alt="Golden Gate Bridge" /></p>
<p>The Bay Area is where you want to be if you are a developer. I know, you’ve heard it a hundred times, but I really have to say it again. This place breathes technology and innovation. I couldn’t expect the effect it has on your everyday live. Being part of a community of people that share the same motivations and interests. You can find daily tech meetups about pretty much any subject you would want.</p>
<p>It’s not anywhere you can just walk down the street and pass by companies like Github, TripAdvisor and Slack on your way to the Grocery Store.</p>
<p>San Francisco is also a really nice city in other aspects. It has beautiful views, awesome food and it’s full of friendly people. Working at an office just by the bay with an amazing view probably helps in admiring what the city has to offer. But be prepared for some chilly winds even during the summer and the famous city fog, that can take away the most sunny day in 5 minutes.</p>
<h3 id="the-work">The Work</h3>
<p><img src="/images/in-content/desk-panda.jpg" alt="My desk" /></p>
<p>A lot earlier than actually getting there, I knew that working at Mozilla would be really interesting. They are one of the main reasons the web is as awesome as it is nowadays. Through Firefox and Javascript, Mozilla allows people to share their thoughts and make the web this open and democratic environment that is changing the world faster than we can keep up. All that mentioning all the projects like Webmakers or the Open Source Support Program, that are pushing people to be more and more an active part of the web.</p>
<p>Having a non-profit full of the smartest people working to make your life and the World a better place is something incredible.</p>
<p>You deal daily with really nice and open people. You do interesting work that have a direct impact on the products. The offices are really nice, with flexible hours, free snacks and drinks, places to hang out and relax, lots of happy hours.</p>
<p>On top of that the University Team organizes awesome events for interns and are always available to help us with any problem.</p>
<p><img src="/images/in-content/mozilla-kitchen.jpg" alt="Kitchen" /></p>
<p>The pay is on par with the other big tech names, plane tickets and housing are paid by the company, they help us a lot with the visa procedures and we get to keep our notebooks (Macbook Pro or equivalents) at the end. We are also showered with SWAG :-). As nice as all this can be, the best part is at the end of the day knowing you’re fighting the good fight.</p>
<p>Oh, and have I mentioned that I had a work week in Canada? During an entire week, members of my team from all around the globe gathered at the Toronto Office to have discussions, meetings and work together. It was a really good experience and really nice to get to know everyone from the team personally.</p>
<h3 id="the-not-so-end">The not-so-end</h3>
<p><img src="/images/in-content/pony-rides.jpg" alt="Pony rides" /></p>
<p>This internship was for sure a life changing experience. Getting to work with people so smart is really fruitful and with all the fun that goes together time goes fast. I made friendships that I hope I’ll carry for life.</p>
<p>But I can’t say it’s the end. Mozilla having this awesome open-source projects, I’ll keep being a volunteer contributor to these projects that are so important for the web environment. I support you to do the same. Contributing to open-source software make you learn a lot about programming, make you part of an amazing community and helps some really important causes.</p>
<p>I’ll finish by leaving you my internship presentation <del>video</del>.</p>
<iframe class="center-image" src="/mozilla-2014/load.html" width="760" height="444" frameborder="0" allowfullscreen=""></iframe>
<p>I can say without doubt that Mozilla offers one of the most fun and valuable internships on the tech industry.</p>
<p>Edit: Mozilla seems to have lost the presentation video, so I replaced it with the slides.</p>It’s more than time I should write something about my Mozilla Internship during this summer. Expect pictures and awesomeness.Dynamic DNS using CloudFlare2014-09-15T03:00:00+00:002014-09-15T03:00:00+00:00https://www.rittme.com/network/raspberry-pi/2014/09/15/cloudflare-ddns<p>Some months ago I finally got my hands at a Raspberry Pi. Much like any other descent person I started trying all sorts of fun and useless projects on it. Finally I settled down with a boring, but useful, XBMC media server.</p>
<p>A well-configured media server completely automates the movie/series watcher pains. This would save me some precious minutes every day, which is every programer dream and goal.</p>
<p>My problem was that some times I feel the need to connect to my Raspberry Pi when I’m not at home. My ssh server was ready for action, but my ISP refuses to provide me with a static IP address. The best solution seemed to be a Dynamic DNS service. Browsing around I could not find a single descent free DDNS. Paying something for the rare occasions where I need a connection seemed wrong.</p>
<p>Then an idea went through my head. I have been a CloudFlare client for some years now and I really enjoy their services. They provide a DNS registry for your domains and a badass API to interact with everything. How hard would it be to use this API as a custom made DDNS?</p>
<p>It turns out it’s not hard at all, and it works pretty well. I found a <a href="https://gist.github.com/riceo/2401865">nice script</a> by Aaron Rice that followed the principle I was looking for. I still needed more features, so I made my own version based on his. It has some fallback IP services, it will only send requests when the IP changes and you can manage a list of different domains.</p>
<figure class="highlight">
<pre><code class="language-python" data-lang="python"><span class="c1">#!/usr/bin/python
</span>
<span class="c1"># Update a set of A records in Cloudflare with the machine current IP address
#
# If you don't know your domain information (like id), you should run:
#
# curl https://www.cloudflare.com/api_json.html \
# -d 'a=rec_load_all' \
# -d 'tkn=CLOUDFLARE_TOKEN' \
# -d 'email=MY_EMAIL' \
# -d 'z=DOMAIN' >> response.json;
#
# In the response.json file you can find all DNS records for the domain.
# Make sure this script runs on a cron job or whenever you get a new IP.
#
# Based on Aaron Rice : cloudflare_dynamic_dns.py (https://gist.github.com/riceo/2401865)
#
# @author Bernardo Rittmeyer <bernardo@rittme.com>
</span>
<span class="kn">import</span> <span class="nn">urllib</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">IP_FILE_NAME</span> <span class="o">=</span> <span class="s">'IP FILE PATH'</span> <span class="c1"># Path to the file that contains the actual/old IP address
</span><span class="n">LOG_FILE_NAME</span> <span class="o">=</span> <span class="s">'LOG FILE PATH'</span> <span class="c1"># Path to the log file
</span><span class="n">TOKEN</span> <span class="o">=</span> <span class="s">"CLOUDFLARE_TOKEN"</span> <span class="c1"># Your cloudflare token
</span><span class="n">EMAIL</span> <span class="o">=</span> <span class="s">"MY_EMAIL"</span> <span class="c1"># Your cloudflare account email
</span>
<span class="c1"># This tuple should have a dictionary for each domain you want to keep up to date
</span><span class="n">domains</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">{</span>
<span class="s">"z"</span> <span class="p">:</span> <span class="s">"DOMAIN"</span><span class="p">,</span> <span class="c1"># zone_name
</span> <span class="s">"id"</span> <span class="p">:</span> <span class="s">"RECORD_ID"</span><span class="p">,</span> <span class="c1"># rec_id
</span> <span class="s">"name"</span><span class="p">:</span> <span class="s">"RECORD_NAME"</span><span class="p">,</span> <span class="c1"># name
</span> <span class="s">"service_mode"</span> <span class="p">:</span> <span class="mi">1</span> <span class="c1"># Status of CloudFlare Proxy, 1 = orange cloud, 0 = grey cloud.
</span> <span class="p">},)</span>
<span class="c1"># External IP Address services we use to find our IP Address (if the first fail we use the next one, and so on)
</span><span class="n">services</span> <span class="o">=</span> <span class="p">(</span><span class="s">"http://ip.appspot.com/"</span><span class="p">,</span> <span class="s">"http://my-ip.heroku.com/"</span><span class="p">,</span> <span class="s">"http://icanhazip.com"</span><span class="p">,</span> <span class="s">"http://checkip.dyndns.org"</span><span class="p">,</span> <span class="s">"http://curlmyip.com"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">log</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">LOG_FILE_NAME</span><span class="p">,</span> <span class="s">"a"</span><span class="p">)</span> <span class="k">as</span> <span class="n">myfile</span><span class="p">:</span>
<span class="n">myfile</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="s">"[%s] %s"</span> <span class="o">%</span> <span class="p">(</span><span class="n">time</span><span class="p">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">"%d/%m/%Y - %H:%M:%S"</span><span class="p">),</span> <span class="n">message</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">ddns_update</span><span class="p">(</span><span class="n">new_ip</span><span class="p">):</span>
<span class="s">"Send the DNS update request to Cloudflare API"</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">"a"</span> <span class="p">:</span> <span class="s">"rec_edit"</span><span class="p">,</span>
<span class="s">"tkn"</span> <span class="p">:</span> <span class="n">TOKEN</span><span class="p">,</span>
<span class="s">"email"</span> <span class="p">:</span> <span class="n">EMAIL</span><span class="p">,</span>
<span class="s">"type"</span> <span class="p">:</span> <span class="s">"A"</span><span class="p">,</span>
<span class="s">"content"</span> <span class="p">:</span> <span class="n">new_ip</span><span class="p">.</span><span class="n">strip</span><span class="p">(),</span>
<span class="s">"ttl"</span> <span class="p">:</span> <span class="mi">1</span>
<span class="p">}</span>
<span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">domains</span><span class="p">:</span>
<span class="n">d</span><span class="p">.</span><span class="n">update</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">dns_response</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">urllib</span><span class="p">.</span><span class="n">urlopen</span><span class="p">(</span><span class="s">"https://www.cloudflare.com/api_json.html"</span><span class="p">,</span> <span class="n">urllib</span><span class="p">.</span><span class="n">urlencode</span><span class="p">(</span><span class="n">d</span><span class="p">)).</span><span class="n">read</span><span class="p">())</span>
<span class="k">if</span> <span class="n">dns_response</span><span class="p">[</span><span class="sa">u</span><span class="s">'result'</span><span class="p">]</span> <span class="o">==</span> <span class="s">"success"</span><span class="p">:</span>
<span class="n">log</span><span class="p">(</span><span class="s">"%s IP updated to %s"</span> <span class="o">%</span> <span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="o">+</span><span class="s">"."</span><span class="o">+</span><span class="n">d</span><span class="p">[</span><span class="n">z</span><span class="p">],</span> <span class="n">new_ip</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">log</span><span class="p">(</span><span class="s">"Error Setting IP for %s"</span> <span class="o">%</span> <span class="n">d</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="o">+</span><span class="s">"."</span><span class="o">+</span><span class="n">d</span><span class="p">[</span><span class="n">z</span><span class="p">])</span>
<span class="k">except</span><span class="p">:</span>
<span class="n">log</span><span class="p">(</span><span class="s">"Error with cloudflare API"</span><span class="p">)</span>
<span class="c1">#Main script
</span>
<span class="c1">#Find the new IP
</span><span class="n">new_ip</span> <span class="o">=</span> <span class="s">""</span>
<span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">services</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">new_ip</span> <span class="o">=</span> <span class="n">urllib</span><span class="p">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">s</span><span class="p">).</span><span class="n">read</span><span class="p">()</span>
<span class="k">except</span> <span class="nb">Exception</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">if</span> <span class="n">new_ip</span><span class="p">:</span>
<span class="k">break</span>
<span class="c1">#Find the old IP
</span><span class="n">old_ip</span> <span class="o">=</span> <span class="s">""</span>
<span class="n">noFile</span> <span class="o">=</span> <span class="bp">False</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">IP_FILE_NAME</span><span class="p">,</span> <span class="s">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">old_ip</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">except</span> <span class="nb">IOError</span><span class="p">:</span>
<span class="n">noFile</span> <span class="o">=</span> <span class="bp">True</span>
<span class="c1">#If IP changed or no IP File, update IP File and send requests to Cloudflare API
</span><span class="k">if</span> <span class="n">new_ip</span> <span class="o">!=</span> <span class="n">old_ip</span> <span class="ow">or</span> <span class="n">noFile</span><span class="p">:</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">IP_FILE_NAME</span><span class="p">,</span><span class="s">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">f</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">new_ip</span><span class="p">)</span>
<span class="n">ddns_update</span><span class="p">(</span><span class="n">new_ip</span><span class="p">)</span>
<span class="n">log</span><span class="p">(</span><span class="s">"IP Address updated to: %s"</span> <span class="o">%</span> <span class="n">new_ip</span><span class="p">)</span></code></pre>
</figure>
<p>You will have to configure it with your own file paths and CloudFlare credentials. You will also have to enter the list of the domains you want to keep updated at the <span class="code">domains</span> tuple. To find all the information you need about you domain you can use the following curl command:</p>
<figure class="highlight">
<pre><code class="language-bash" data-lang="bash">curl https://www.cloudflare.com/api_json.html <span class="se">\</span>
<span class="nt">-d</span> <span class="s1">'a=rec_load_all'</span> <span class="se">\</span>
<span class="nt">-d</span> <span class="s1">'tkn=CLOUDFLARE_TOKEN'</span> <span class="se">\</span>
<span class="nt">-d</span> <span class="s1">'email=MY_EMAIL'</span> <span class="se">\</span>
<span class="nt">-d</span> <span class="s1">'z=DOMAIN'</span> <span class="o">>></span> response.json<span class="p">;</span></code></pre>
</figure>
<p>You should replace <span class="code">CLOUDFLARE_TOKEN</span>, <span class="code">MY_EMAIL</span> and <span class="code">DOMAIN</span> with the correct values for you. In the response.json file you can find all the DNS records for the domain.</p>
<p>Now, to be always up to date we have to make sure this script runs on a cron job. For that you should run:</p>
<figure class="highlight">
<pre><code class="language-bash" data-lang="bash">crontab <span class="nt">-e</span></code></pre>
</figure>
<p>This will open your crontab for editing, and you can add the following line at the end of it:</p>
<figure class="highlight">
<pre><code class="language-bash" data-lang="bash"><span class="k">*</span>/15 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> python /path/to/your/script</code></pre>
</figure>
<p>Include the correct path to your script at the defined place. If you want an update frequency different from 15 minutes, you can change this value as well.</p>
<p>Now you should have your domain always pointing to your IP address and your machine accessible to the outside world. Just, please, don’t forget about the security concerns of opening your doors and take every reasonable precaution not to have strangers getting into hour home.</p>Some months ago I finally got my hands at a Raspberry Pi. Much like any other descent person I started trying all sorts of fun and useless projects on it. Finally I settled down with a boring, but useful, XBMC media server.