HQarroum/Gravatar

View on GitHub
lib/index.js

Summary

Maintainability
A
0 mins
Test Coverage
/**
 * ///////////////////////////////////////
 * ////////// Gravatar module ////////////
 * ///////////////////////////////////////
 *
 * This module offers object caching mechanisms for
 * third-party modules. It also allows to set a time-to-live
 * to the cached objects.
 */

/**
 * The Gravatar service base URL.
 */
const serviceUrl = 'https://secure.gravatar.com';

/**
 * The default values associated with the
 * request.
 */
const defaults = {

  /**
   * The default behaviour when no image is
   * associated with the given e-mail address.
   */
  defaultIcon: '404',

  /**
   * Defines whether to retrieve an avatar given
   * its category, or rating.
   * See https://en.gravatar.com/site/implement/images#rating
   */
  rating: 'G',

  /**
   * Defines the size of the image in pixels.
   */
  size: '80'
};

/**
 * Helper used to stringify the key/value pairs
 * of an object into a query string.
 */
const encodeParameters = (p) => Object.entries(p).map((kv) => kv.map(encodeURIComponent).join('=')).join('&');

/**
 * Returns a MD5 hash associated with the given input.
 */
const md5 = (s) => { var k = [], i = 0; for (; i < 64;) { k[i] = 0 | Math.sin(++i % Math.PI) * 4294967296; } var b, c, d, h = [b = 0x67452301, c = 0xEFCDAB89, ~b, ~c], words = [], j = unescape(encodeURI(s)) + '\x80', a = j.length; s = (--a / 4 + 2) | 15; words[--s] = a * 8; for (; ~a;) { words[a >> 2] |= j.charCodeAt(a) << 8 * a--; } for (i = j = 0; i < s; i += 16) { a = h; for (; j < 64; a = [d = a[3], (b + ((d = a[0] + [b & c | ~b & d, d & b | ~d & c, b ^ c ^ d, c ^ (b | ~d)][a = j >> 4] + k[j] + ~~words[i | [j, 5 * j + 1, 3 * j + 5, 7 * j][a] & 15]) << (a = [7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21][4 * a + j++ % 4]) | d >>> -a)), b, c]) { b = a[1] | 0; c = a[2]; } for (j = 4; j;) h[--j] += a[j]; } for (s = ''; j < 32;) { s += ((h[j >> 3] >> ((1 ^ j++) * 4)) & 15).toString(16); } return s; }

/**
 * Returns a MD5-hashed representation
 * of the given e-mail address according to
 * Gravatar's specifications.
 * See https://en.gravatar.com/site/implement/hash/
 */
const hash = (email) => md5(email.trim().toLowerCase());

/**
 * Returns the result of fetch given the environment.
 */
const fetch = async function () {
  return (typeof window !== 'undefined' ? window.fetch(...arguments) : await import('node-fetch').then((f) => f.default(...arguments)));
};

export default {
  /**
   * Constructs the user avatar URL associated with
   * the given e-mail address.
   */
  url(email, options = {}) {
    const opts = {
      d: options.defaultIcon || defaults.defaultIcon,
      r: options.rating || defaults.rating,
      s: options.size || defaults.size
    };

    return (`${serviceUrl}/avatar/${hash(email)}?${encodeParameters(opts)}`);
  },

  /**
  * Retrieves the personal informations associated
  * with the owner of the given e-mail address.
  */
  async profiles(email, options = { format: 'json' }) {
    const url = `${serviceUrl}/${(options.hash === false ? email : hash(email))}.${options.format}`;

    return (fetch(url)
      .then((res) => res.json())
      .then((data) => data.entry));
  },

  /**
   * Tries to resolve the given e-mail address using the
   * given options. This method is handy to determine
   * whether an avatar actually exists on the Gravatar
   * service for the given e-mail address.
   * @returns a promise resolved if the avatar was able to
   * be retrieved, and rejected if the retrieval failed.
   */
  async resolve(email, options = {}) {
    const url = this.url(email, options);

    return (fetch(url, { method: 'HEAD' }).then((response) => {
      return (response.status === 200) ? url : Promise.reject('Avatar does not exist');
    }));
  }
};