HaveIBeenPwnd.com API
Refer to my previous post on the Salesforce REST API for a full Dockerized Rails setup.
Here is a wrapper for the “Have I Been Pwnd” API.
Note that the API key is in encrypted credentials and also in a private method so as not to be inadvertently exposed outside the Class.
require 'uri'
require 'net/http'
require 'digest'
class HibpApi
BASE_URL = 'https://haveibeenpwned.com/api/v3/'
BREACHED_ACCOUNT_URL = "#{BASE_URL}/breachedaccount/"
def pwnd_password?(password)
base_url = 'https://api.pwnedpasswords.com/range'
sha1_password = Digest::SHA1.hexdigest(password).upcase
prefix = sha1_password[0, 5]
suffix = sha1_password[5..-1]
url = URI("https://api.pwnedpasswords.com/range/#{prefix}")
response = Net::HTTP.get(url)
found = false
breach_count = 0
response.each_line do |line|
hash_suffix, count = line.split(':')
next unless hash_suffix.strip == suffix
Rails.logger.info "Password found #{count.strip} times."
found = true
breach_count += count.to_i
break
end
Rails.logger.info('Password not been found in breach') unless found
{ found:, breach_count: }
end
def pwnd_email_account?(email:)
found = false
url = URI("#{BREACHED_ACCOUNT_URL}/#{email}")
response = send_get_request(url)
hsh_ary = JSON.parse(response.body)
breaches = hsh_ary.pluck('Name')
found = true if breaches.count.positive?
{ found:, breaches: }
end
private
def api_key
Rails.application.credentials[:hibp_api_key]
end
def send_get_request(url)
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Get.new(url)
request['hibp-api-key'] = api_key
https.request(request)
end
end
Here are the specs.
The email address is an environmental variable using dotenv-rails
.
# app/services/hibp_api.rb
require 'rails_helper'
RSpec.describe HibpApi do
before do
@service = described_class.new
end
describe 'Password' do
it 'checks whether "password123" has been pwnd', focus: false do
res = @service.pwnd_password?('password123')
expect(res[:found]).to be true
end
end
describe 'Email Account' do
it 'checks whether personal account has been pwnd', focus: false do
email = ENV.fetch('TEST_EMAIL_ACCOUNT', nil)
res = @service.pwnd_email_account?(email:)
expect(res[:found]).to be true
end
end
end
Published on 12 Sep 2024
all tags
100daysofcode activerecord android annoyances api apt arch array artix atom az3w backend bash blog browser bug callback career ci-cd cli cloud code coding config configuration cp crud cryptography css csv database db design devops django docker email erp feelsgood filter fugitive gif gist git gnome gnome pomodoro grep hebrew http ide isbn-fetcher iso javascript job search js kanban kindle koans learning linkedin linux logger manjaro map markdown microservices mobi mtp neovim nodejs nvchad packages panda pastbin patch portfolio post postgres pytest python rails reduce refactoring reflections rest routes rspec ruby salesforce script scripting security sed shell sql string_replacement study tdd terminal testing tmux ttd version_control vim vim sort walkthrough webdev workflow