text: 'use strict';
  
  var crypto = require('crypto');
  var b32 = require('thirty-two');
  
  // Generate a key
  function generateOtpKey() {
    // 20 cryptographically random binary bytes (160-bit key)
    var key = crypto.randomBytes(20);
  
    return key;
  }
  
  // Text-encode the key as base32 (in the style of Google Authenticator - same as Facebook, Microsoft, etc)
  function encodeGoogleAuthKey(bin) {
    // 32 ascii characters without trailing '='s
    var base32 = b32.encode(bin).toString('utf8').replace(/=/g, '');
  
    // lowercase with a space every 4 characters
    var key = base32.toLowerCase().replace(/(\w{4})/g, "$1 ").trim();
  
    return key;
  }
  
  function generateGoogleAuthKey() {
    return encodeGoogleAuthKey(generateOtpKey());
  }
  
  // Binary-decode the key from base32 (Google Authenticator, FB, M$, etc)
  function decodeGoogleAuthKey(key) {
    // decode base32 google auth key to binary
    var unformatted = key.replace(/\W+/g, '').toUpperCase();
    var bin = b32.decode(unformatted);
  
    return bin;
  }
  
  // Generate a Google Auth Token
  function generateGoogleAuthToken(key) {
    var bin = decodeGoogleAuthKey(key);
    var notp = require('notp');
  
    return notp.totp.gen(bin);
  }
  
  // Verify a Google Auth Token
  function verifyGoogleAuthToken(key, token) {
    var bin = decodeGoogleAuthKey(key);
    var notp = require('notp');
  
    token = token.replace(/\W+/g, '');
  
    // window is +/- 1 period of 30 seconds
    return notp.totp.verify(token, bin, { window: 1, time: 30 });
  }
  
  module.exports.generateKey = generateGoogleAuthKey;
  module.exports.generateToken = generateGoogleAuthToken;
  module.exports.verifyToken = verifyGoogleAuthToken;
  module.exports.generateTotpUri = function (secret, accountName, issuer, algo, digits, period) {
    // Full OTPAUTH URI spec as explained at
    // https://github.com/google/google-authenticator/wiki/Key-Uri-Format
    return 'otpauth://totp/'
      + encodeURI(issuer || '') + ':' + encodeURI(accountName || '')
      + '?secret=' + secret.replace(/[\s\.\_\-]+/g, '').toUpperCase()
      + '&issuer=' + encodeURIComponent(issuer || '')
      + '&algorithm=' + (algo || 'SHA1')
      + '&digits=' + (digits || 6)
      + '&period=' + (period || 30)
      ;  
  };
  