This is a guest post from CodePen community member Nour Soud.

Hackers (the bad kind) have a lot of tools and techniques to try to guess our passwords. Setting up a secure, long and complicated password is the least we can do if we want to protect ourselves and our data.

We should also have a unique password for each app/service we use to make sure we don’t lose everything if one of the accounts got compromised.

In my case, whenever I try to generate a secure password, I always either:

Use 1password’s password generator:

Pros Cons
Nice design You have to have 1password installed which is paid and not everyone can afford it.
Simple Password generator with the main and basic options You have to login to 1password before generating the password

Or, Google “good password generator”, pick the top listed and use it:

Pros Cons
No need for prior installation. Not user-friendly
Too many options that people rarely care about

None of the above options felt perfect for me, and I had the feeling that I can combine the pros of both in one simple web app.

The Implementation

I’ve always loved experimenting with Vue.js, and I just launched a todo-list manager using Vue.js a month before, so I thought it would be the best approach to take.

As always, I jumped to CodePen and started building the app. It took me a while to get the design right, I changed it a lot and played with it a lot.

Designing the range-sliders took me some time to do, but with the plenty of contributions on CodePen, I gathered inspiration from other people's Pens (like "CSS Range Slider" by Sean Stopnik) and one of my own, and came up with my sliders.

The initial design
The final look

See the Pen The Password Genie - Vue.js by Nour Soud (@nourabusoud) on CodePen.

Going Live

I first published the password generator on CodePen so people can engage with and learn from my experiment, and also perhaps fork it and make a better version of it.

I wanted the password generator to be really used by people, so I thought of hosting it on GitHub pages would be the perfect and simplest way to do it, and in the future if it had traffic I might get it it’s own domain name for better accessibility!

I then shared it on Twitter and I got lots of great feedback from awesome designers and developers! The amount of joy that gave me was unbelievable!

Some people even requested a browser extension. I found this to be a chance here to learn something new as I have to admit that I never even looked on how these extensions are built and always thought they would be so hard to make!

The Chrome Extension

I did a bit of research on how to make Chrome extensions. It looked easy at first, but I had some decisions to make.

Usually if you want to make a chrome extension what you have to do is:

  1. Create a popup.html page and put your HTML there. There should be no inline scripts at all.
  2. Create a popup.js file to put you JavaScript code in.
  3. Create a manifest.json file to describe your plugin.

Example:

    {
      "manifest_version": 2,
      "name": "The Password Genie",
      "description": "Secure and instant password generator",
      "version": "1.0",

      "browser_action": {
       "default_icon": "icon.png",
       "default_popup": "popup.html"
      },
      "permissions": []
    }

You’ll need to create the icon listed there in the manifest as well.

In my project, I’ve used Vue by directly including it via a CDN in the <script> tag, this way allows you to create your Vue app in the same HTML page, example:

    <body>
        <div id="app">
            {{ message }}
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.js"></script>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    message: 'Hello World!'
                }
            })
        </script>
    </body>

This wasn’t possible for building the chrome extension, as you can’t include inline scripts due to Content-Security-Policy (CSP). I had to find another solution. Either do it with plain JavaScript or create a Vue project using the runtime-only version. I actually did both, but ended up going live with the Vue option.

Building the Chrome Extension

I did some research and found this really good step-by-step article. I’ll explain it in details below as I’ve modified the process a little:

1: Install the Chrome Extension generator. You can find the steps in the readme.

2: Install additional packages:

    npm install --save webpack webpack-stream babel-loader vue vue-loader css-loader vue-template-compiler babel-preset-env

3: In gulpfile.babel.js, at the top of the file, add these imports:

    import webpackStream from 'webpack-stream';
    import webpack from 'webpack'

4: Replace the following tasks in gulpfile.babel.js:

Babel task

    gulp.task('babel', () => {
      return gulp.src('app/scripts.babel')
        .pipe(webpackStream(require('./webpack.config.js'), webpack)
          .on('error', function (err) {
            console.log(err);
            this.emit('end');
          }))
        .pipe(gulp.dest('app/scripts/'))
    });

Watch task to watch for .vue extension changes

    gulp.task('watch', ['lint', 'babel'], () => {
      $.livereload.listen();

      gulp.watch([
        'app/*.html',
        'app/scripts/**/*.js',
        'app/scripts/**/*.vue',
        'app/images/**/*',
        'app/styles/**/*',
        'app/_locales/**/*.json'
      ]).on('change', $.livereload.reload);

      gulp.watch(['app/scripts.babel/**/*.js', 'app/scripts.babel/**/*.vue'], ['lint', 'babel']);
      gulp.watch('bower.json', ['wiredep']);
    });

    gulp.task('size', () => {
      return gulp.src('dist/**/*').pipe($.size({title: 'build', gzip: true}));
    });

And modify the lint function

    gulp.task('lint', lint('app/scripts.babel/**/*.js', {
      env: {
        es6: true
      },
      parserOptions: {
        sourceType: 'module'
      }
    }));

5: Create webpack.config.js in the project root folder and add the following code to it:

    module.exports = {
      context: __dirname + '/app/scripts.babel/',
      entry: {
        chromereload: './chromereload.js',
        popup: './popup.js',
      },
      output: { filename: '[name].js' },
      module: {
        rules: [{
          test: /\.js$/,
          loader: 'babel-loader'
        }, {
          test: /\.vue$/,
          loader: 'vue-loader'
        }]
      }
    }

6: Adding in my Vue application:

I created my main Vue component in: app/scripts.babel/popup/Popup.vue, then I copied the code from my Pen with some changes:

  • Component template should only contain exactly one root element, so everything in my case should be under the <section> tag
  • Since I’m creating a component here I should use export default to declare it.
    <template>
      <section class="wrapper">
      <!-- my code went here
      ......... 
      -->
      </section>
    </template>

    <script>
    export default {
      data() {
      //....
      }
    }
    </script>

Then I created my app instant in my popup.html file

    <div id="app"></div>

I used the code below in my popup.js file to render my new component in my application and creating a new Vue instance.

    import Vue from 'vue';
    import Popup from './popup/Popup.vue';

    new Vue({
        el: '#app',
        render: c => c(Popup)
    });

Testing the Extension

First I had to build the application first using:

gulp build

I used the /dist/ folder as my source for the Chrome extension.

  • In Chrome I went to: chrome://extensions/
  • Enabled Developer mode
  • Loaded the app from the /dist/ folder as an unpacked extension

Adjusting the Design

The password generator worked perfectly, but looked very big for an extension. So, I had to tweak my design to make it more extension-like. I had to adjust the sizes, and clean it up by removing some unnecessary elements to make it as compact and user-friendly as possible.

Before
After

Voilà, Now I have a working good-looking password generator that’s only one click away!

Links