mozilla / blurts-server

Mozilla Monitor arms you with tools to keep your personal information safe. Find out what hackers already know about you and learn how to stay a step ahead of them.
https://monitor.mozilla.org
Mozilla Public License 2.0
732 stars 206 forks source link

Add URL for breach to detail page #1119

Closed changecourse closed 5 years ago

changecourse commented 5 years ago

Make it easier for folks to navigate to the website of a given breach, via the breach detail page.

Screen Shot 2019-07-16 at 1 32 09 PM

Zeplin: https://zpl.io/a7WP5m8

pdehaan commented 5 years ago

also, lets add the rel="nofollow" on the outbound link, so we don't give them any SEO points.

Per Google's own https://support.google.com/webmasters/answer/96569?hl=en

What are Google's policies and some specific examples of nofollow usage?

Here are some cases in which you might want to consider using nofollow:

  • Untrusted content: If you can't or don't want to vouch for the content of pages you link to from your site — for example, untrusted user comments or guestbook entries — you should nofollow those links. This can discourage spammers from targeting your site, and will help keep your site from inadvertently passing PageRank to bad neighborhoods on the web. In particular, comment spammers may decide not to target a specific content management system or blog service if they can see that untrusted links in that service are nofollowed. If you want to recognize and reward trustworthy contributors, you could decide to automatically or manually remove the nofollow attribute on links posted by members or users who have consistently made high-quality contributions over time.
pdehaan commented 5 years ago

Another casual observation... We only get a breach.Domain back from HIBP API, which is a protocol-less "evite.com":

// via https://haveibeenpwned.com/api/v2/breach/Evite
{
  Name: "Evite",
  Title: "Evite",
  Domain: "evite.com",
  ...
}

We'd need to prefix that domain with http:// (and not https:// or protocol-less //${Domain}).

I tried with http://${breach.Domain} and got 56 results with a non 2xx or 3xx response code.

20 domains were timeouts (exceeded 5000ms): DOMAIN | MESSAGE | STATUS_CODE :------|:--------|:-----------:| http://battlefieldheroes.com/ | timeout of 5000ms exceeded | http://bolt.cd/ | timeout of 5000ms exceeded | http://7k7k.com/ | timeout of 5000ms exceeded | http://btc-e.com/ | timeout of 5000ms exceeded | http://crackingforum.com/ | timeout of 5000ms exceeded | http://gamerzplanet.net/ | timeout of 5000ms exceeded | http://game-tuts.com/ | timeout of 5000ms exceeded | http://geekedin.net/ | timeout of 5000ms exceeded | http://play-gar.com/ | timeout of 5000ms exceeded | http://hautelook.com/ | timeout of 5000ms exceeded | http://heroesofgaia.com/ | timeout of 5000ms exceeded | http://i-dressup.com/ | timeout of 5000ms exceeded | http://myfha.net/ | timeout of 5000ms exceeded | http://myrepospace.com/ | timeout of 5000ms exceeded | http://163.com/ | timeout of 5000ms exceeded | http://pokemonnegro.com/ | timeout of 5000ms exceeded | http://thecandidboard.com/ | timeout of 5000ms exceeded | http://intgovforum.org/ | timeout of 5000ms exceeded | http://win7vista.com/ | timeout of 5000ms exceeded | http://xboxscene.com/ | timeout of 5000ms exceeded |
19 domains were ENOTFOUND errors: DOMAIN | MESSAGE | STATUS_CODE :------|:--------|:-----------:| http://17app.co/ | getaddrinfo ENOTFOUND 17app.co 17app.co:80 | http://astropid.com/ | getaddrinfo ENOTFOUND astropid.com astropid.com:80 | http://forums.boxee.com/ | getaddrinfo ENOTFOUND forums.boxee.com forums.boxee.com:80 | http://cloudpets.com/ | getaddrinfo ENOTFOUND cloudpets.com cloudpets.com:80 | http://digimon.co.in/ | getaddrinfo ENOTFOUND digimon.co.in digimon.co.in:80 | http://fhostingesps6bly.onion/ | getaddrinfo ENOTFOUND fhostingesps6bly.onion fhostingesps6bly.onion http://imesh.com/ | getaddrinfo ENOTFOUND imesh.com imesh.com:80 | http://knowncircle.com/ | getaddrinfo ENOTFOUND knowncircle.com knowncircle.com:80 | http://lizardstresser.su/ | getaddrinfo ENOTFOUND lizardstresser.su lizardstresser.su:80 | http://mindjolt.com/ | getaddrinfo ENOTFOUND mindjolt.com mindjolt.com:80 | http://minecraftpeforum.net/ | getaddrinfo ENOTFOUND minecraftpeforum.net minecraftpeforum.net:80 | http://modbsolutions.com/ | getaddrinfo ENOTFOUND modbsolutions.com modbsolutions.com:80 | http://nulled.cr/ | getaddrinfo ENOTFOUND nulled.cr nulled.cr:80 | http://onverse.com/ | getaddrinfo ENOTFOUND onverse.com onverse.com:80 | http://ordineavvocatiroma.it/ | getaddrinfo ENOTFOUND ordineavvocatiroma.it ordineavvocatiroma.it:80 | http://rivercitymediaonline.com/ | getaddrinfo ENOTFOUND rivercitymediaonline.com rivercitymediaonli ne.com:80 | http://seedpeer.eu/ | getaddrinfo ENOTFOUND seedpeer.eu seedpeer.eu:80 | http://torrent-invites.com/ | getaddrinfo ENOTFOUND torrent-invites.com torrent-invites.com:80 | http://victoryphones.com/ | getaddrinfo ENOTFOUND victoryphones.com victoryphones.com:80 |
5 results were ECONNREFUSED or ENETUNREACH errors: DOMAIN | MESSAGE | STATUS_CODE :------|:--------|:-----------:| http://aipai.com/ | connect ECONNREFUSED 120.92.118.145:80 | http://dvd-shop.ch/ | connect ECONNREFUSED 78.46.95.8:80 | http://staminus.net/ | connect ECONNREFUSED 72.8.190.19:80 | http://thewarinc.com/ | connect ECONNREFUSED 78.46.98.241:80 | http://russianamerica.com/ | connect ENETUNREACH 64.34.89.167:80 |
9 results were 308 or 4xx or 5xx or a misc "Parse Error" errors: DOMAIN | MESSAGE | STATUS_CODE :------|:--------|:-----------:| http://crackcommunity.com/ | | 503 http://mortalonline.com/ | | 503 http://nextgenupdate.com/ | | 503 http://paddypower.com/ | Parse Error | http://sterkinekor.co.za/ | | 530 http://viewfines.co.za/ | | 403 http://vtechda.com/ | | 404 http://whitepages.com/ | | 416 http://yatra.com/ | http://www.yatra.com/ | 308

When I tried to make the default protocol HTTPS (a la https://${breach.Domain}), the number of HTTP errors went from 56 to 125:


domain-redirect-http-vs-https.js ```js const axios = require("axios"); main(); async function getBreaches() { const res = await axios.get("https://haveibeenpwned.com/api/v2/breaches"); return res.data.filter(breach => breach.Domain); } async function main() { const breaches = await getBreaches(); for (const breach of breaches) { const res = await checkDomain(breach); switch (res.status) { case 200: case 301: case 302: case 303: break; default: console.log(`${res.domain} | ${res.location || res.error || ""} | ${res.status}`); break; } } } async function checkDomain(breach, protocol="https") { const url = new URL(`${protocol}://${breach.Domain}`).href; try { const res = await axios.get(url, { maxRedirects: 0, // 5 second request timeout timeout: 5000, validateStatus: null }); return { domain: url, location: (res.status === 200) ? url : res.headers.location, status: res.status, }; } catch (err) { return { domain: url, error: err.message, status: "" }; } } ```